Merge branch 'develop'
This commit is contained in:
@@ -7,12 +7,12 @@ use std::vec::Vec;
|
||||
pub struct Frame {
|
||||
pub global_index: usize,
|
||||
pub e: usize,
|
||||
pub cp: CodePtr,
|
||||
pub cp: LocalCodePtr,
|
||||
perms: Vec<Addr>
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn new(global_index: usize, fr: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
||||
fn new(global_index: usize, fr: usize, e: usize, cp: LocalCodePtr, n: usize) -> Self {
|
||||
Frame {
|
||||
global_index,
|
||||
e: e,
|
||||
@@ -29,7 +29,7 @@ impl AndStack {
|
||||
AndStack(Vec::new())
|
||||
}
|
||||
|
||||
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
||||
pub fn push(&mut self, global_index: usize, e: usize, cp: LocalCodePtr, n: usize) {
|
||||
let len = self.0.len();
|
||||
self.0.push(Frame::new(global_index, len, e, cp, n));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ pub type Var = String;
|
||||
|
||||
pub type Specifier = u32;
|
||||
|
||||
pub const MAX_ARITY: usize = 63;
|
||||
|
||||
pub const XFX: u32 = 0x0001;
|
||||
pub const XFY: u32 = 0x0002;
|
||||
pub const YFX: u32 = 0x0004;
|
||||
@@ -158,11 +160,24 @@ pub struct Module {
|
||||
pub op_dir: OpDir
|
||||
}
|
||||
|
||||
pub fn default_op_dir() -> OpDir {
|
||||
let module_name = clause_name!("builtins");
|
||||
let mut op_dir = OpDir::new();
|
||||
|
||||
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200, module_name.clone()));
|
||||
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200, module_name.clone()));
|
||||
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200, module_name.clone()));
|
||||
|
||||
op_dir
|
||||
}
|
||||
|
||||
pub static BUILTINS: &str = include_str!("./lib/builtins.pl");
|
||||
|
||||
impl Module {
|
||||
pub fn new(module_decl: ModuleDecl) -> Self {
|
||||
Module { module_decl,
|
||||
code_dir: ModuleCodeDir::new(),
|
||||
op_dir: OpDir::new() }
|
||||
op_dir: default_op_dir() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,11 +207,13 @@ pub trait SubModuleUser {
|
||||
// returns true on successful import.
|
||||
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
||||
let name = name.defrock_brackets();
|
||||
let mut found_op = false;
|
||||
|
||||
{
|
||||
let mut insert_op_dir = |fix| {
|
||||
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), fix)) {
|
||||
self.op_dir().insert((name.clone(), fix), op_data.clone());
|
||||
found_op = true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -212,7 +229,7 @@ pub trait SubModuleUser {
|
||||
self.insert_dir_entry(name, arity, code_data.clone());
|
||||
true
|
||||
} else {
|
||||
false
|
||||
found_op
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +480,7 @@ pub enum ParserError
|
||||
{
|
||||
Arithmetic(ArithmeticError),
|
||||
BackQuotedString,
|
||||
BuiltInArityMismatch(&'static str),
|
||||
// BuiltInArityMismatch(&'static str),
|
||||
UnexpectedChar(char),
|
||||
UnexpectedEOF,
|
||||
IO(IOError),
|
||||
@@ -559,59 +576,71 @@ pub enum Term {
|
||||
Var(Cell<VarReg>, Rc<Var>)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum InlinedClauseType {
|
||||
CompareNumber(CompareNumberQT),
|
||||
IsAtom,
|
||||
IsAtomic,
|
||||
IsCompound,
|
||||
IsInteger,
|
||||
IsRational,
|
||||
IsString,
|
||||
IsFloat,
|
||||
IsNonVar,
|
||||
IsVar,
|
||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||
IsAtom(RegType),
|
||||
IsAtomic(RegType),
|
||||
IsCompound(RegType),
|
||||
IsInteger(RegType),
|
||||
IsRational(RegType),
|
||||
IsString(RegType),
|
||||
IsFloat(RegType),
|
||||
IsNonVar(RegType),
|
||||
IsVar(RegType),
|
||||
}
|
||||
|
||||
impl InlinedClauseType {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
&InlinedClauseType::CompareNumber(qt) => qt.name(),
|
||||
&InlinedClauseType::IsAtom => "atom",
|
||||
&InlinedClauseType::IsAtomic => "atomic",
|
||||
&InlinedClauseType::IsCompound => "compound",
|
||||
&InlinedClauseType::IsInteger => "integer",
|
||||
&InlinedClauseType::IsRational => "rational",
|
||||
&InlinedClauseType::IsString => "string",
|
||||
&InlinedClauseType::IsFloat => "float",
|
||||
&InlinedClauseType::IsNonVar => "nonvar",
|
||||
&InlinedClauseType::IsVar => "var"
|
||||
&InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
|
||||
&InlinedClauseType::IsAtom(..) => "atom",
|
||||
&InlinedClauseType::IsAtomic(..) => "atomic",
|
||||
&InlinedClauseType::IsCompound(..) => "compound",
|
||||
&InlinedClauseType::IsInteger (..) => "integer",
|
||||
&InlinedClauseType::IsRational(..) => "rational",
|
||||
&InlinedClauseType::IsString(..) => "string",
|
||||
&InlinedClauseType::IsFloat (..) => "float",
|
||||
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
||||
&InlinedClauseType::IsVar(..) => "var"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(name: &str, arity: usize) -> Option<Self> {
|
||||
let r1 = temp_v!(1);
|
||||
let r2 = temp_v!(2);
|
||||
|
||||
let a1 = ArithmeticTerm::Reg(r1);
|
||||
let a2 = ArithmeticTerm::Reg(r2);
|
||||
|
||||
match (name, arity) {
|
||||
(">", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan)),
|
||||
("<", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan)),
|
||||
(">=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual)),
|
||||
("<=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual)),
|
||||
("=\\=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual)),
|
||||
("=:=", 2) => Some(InlinedClauseType::CompareNumber(CompareNumberQT::Equal)),
|
||||
("atom", 1) => Some(InlinedClauseType::IsAtom),
|
||||
("atomic", 1) => Some(InlinedClauseType::IsAtomic),
|
||||
("compound", 1) => Some(InlinedClauseType::IsCompound),
|
||||
("integer", 1) => Some(InlinedClauseType::IsInteger),
|
||||
("rational", 1) => Some(InlinedClauseType::IsRational),
|
||||
("string", 1) => Some(InlinedClauseType::IsString),
|
||||
("float", 1) => Some(InlinedClauseType::IsFloat),
|
||||
("nonvar", 1) => Some(InlinedClauseType::IsNonVar),
|
||||
("var", 1) => Some(InlinedClauseType::IsVar),
|
||||
(">", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, a1, a2)),
|
||||
("<", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, a1, a2)),
|
||||
(">=", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual,a1, a2)),
|
||||
("=<", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, a1, a2)),
|
||||
("=\\=", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, a1, a2)),
|
||||
("=:=", 2) =>
|
||||
Some(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, a1, a2)),
|
||||
("atom", 1) => Some(InlinedClauseType::IsAtom(r1)),
|
||||
("atomic", 1) => Some(InlinedClauseType::IsAtomic(r1)),
|
||||
("compound", 1) => Some(InlinedClauseType::IsCompound(r1)),
|
||||
("integer", 1) => Some(InlinedClauseType::IsInteger(r1)),
|
||||
("rational", 1) => Some(InlinedClauseType::IsRational(r1)),
|
||||
("string", 1) => Some(InlinedClauseType::IsString(r1)),
|
||||
("float", 1) => Some(InlinedClauseType::IsFloat(r1)),
|
||||
("nonvar", 1) => Some(InlinedClauseType::IsNonVar(r1)),
|
||||
("var", 1) => Some(InlinedClauseType::IsVar(r1)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum CompareNumberQT {
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
@@ -634,7 +663,7 @@ impl CompareNumberQT {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum CompareTermQT {
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
@@ -665,6 +694,7 @@ pub enum QueryTerm {
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>),
|
||||
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
||||
UnblockedCut(Cell<VarReg>),
|
||||
GetLevelAndUnify(Cell<VarReg>, Rc<Var>),
|
||||
Jump(JumpStub)
|
||||
}
|
||||
|
||||
@@ -673,7 +703,8 @@ impl QueryTerm {
|
||||
match self {
|
||||
&QueryTerm::Clause(_, _, ref subterms) => subterms.len(),
|
||||
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => 0,
|
||||
&QueryTerm::Jump(ref vars) => vars.len()
|
||||
&QueryTerm::Jump(ref vars) => vars.len(),
|
||||
&QueryTerm::GetLevelAndUnify(..) => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -683,13 +714,100 @@ pub struct Rule {
|
||||
pub clauses: Vec<QueryTerm>
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ClauseType {
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum SystemClauseType {
|
||||
CheckCutPoint,
|
||||
GetSCCCleaner,
|
||||
InstallSCCCleaner,
|
||||
InstallInferenceCounter,
|
||||
RemoveCallPolicyCheck,
|
||||
RemoveInferenceCounter,
|
||||
RestoreCutPolicy,
|
||||
SetCutPoint(RegType),
|
||||
InferenceLevel,
|
||||
CleanUpBlock,
|
||||
EraseBall,
|
||||
Fail,
|
||||
GetBall,
|
||||
GetCurrentBlock,
|
||||
GetCutPoint,
|
||||
InstallNewBlock,
|
||||
ResetBlock,
|
||||
SetBall,
|
||||
SkipMaxList,
|
||||
Succeed,
|
||||
UnwindStack
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
pub fn fixity(&self) -> Option<Fixity> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||
&SystemClauseType::InstallInferenceCounter =>
|
||||
clause_name!("$install_inference_counter"),
|
||||
&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::InferenceLevel => clause_name!("$inference_level"),
|
||||
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
|
||||
&SystemClauseType::EraseBall => clause_name!("$erase_ball"),
|
||||
&SystemClauseType::Fail => clause_name!("$fail"),
|
||||
&SystemClauseType::GetBall => clause_name!("$get_ball"),
|
||||
&SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
|
||||
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
||||
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
||||
&SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
|
||||
&SystemClauseType::Succeed => clause_name!("$succeed"),
|
||||
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
||||
match (name, arity) {
|
||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
||||
("$install_scc_cleaner", 2) =>
|
||||
Some(SystemClauseType::InstallSCCCleaner),
|
||||
("$install_inference_counter", 3) =>
|
||||
Some(SystemClauseType::InstallInferenceCounter),
|
||||
("$remove_call_policy_check", 1) =>
|
||||
Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||
("$remove_inference_counter", 1) =>
|
||||
Some(SystemClauseType::RemoveInferenceCounter),
|
||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
||||
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
||||
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
||||
("$fail", 0) => Some(SystemClauseType::Fail),
|
||||
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||
("$set_ball", 1) => Some(SystemClauseType::SetBall),
|
||||
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum BuiltInClauseType {
|
||||
AcyclicTerm,
|
||||
Arg,
|
||||
CallN,
|
||||
CallWithInferenceLimit,
|
||||
Catch,
|
||||
Compare,
|
||||
CompareTerm(CompareTermQT),
|
||||
CyclicTerm,
|
||||
@@ -698,16 +816,20 @@ pub enum ClauseType {
|
||||
Eq,
|
||||
Functor,
|
||||
Ground,
|
||||
Inlined(InlinedClauseType),
|
||||
Is,
|
||||
Is(RegType, ArithmeticTerm),
|
||||
KeySort,
|
||||
NotEq,
|
||||
Sort,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ClauseType {
|
||||
BuiltIn(BuiltInClauseType),
|
||||
CallN,
|
||||
Inlined(InlinedClauseType),
|
||||
Op(ClauseName, Fixity, CodeIndex),
|
||||
Named(ClauseName, CodeIndex),
|
||||
SetupCallCleanup,
|
||||
SkipMaxList,
|
||||
Sort,
|
||||
Throw,
|
||||
System(SystemClauseType)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -775,78 +897,122 @@ impl ClauseName {
|
||||
}
|
||||
}
|
||||
|
||||
impl ClauseType {
|
||||
pub fn fixity(&self) -> Option<Fixity> {
|
||||
impl BuiltInClauseType {
|
||||
fn fixity(&self) -> Option<Fixity> {
|
||||
match self {
|
||||
&ClauseType::Compare | &ClauseType::CompareTerm(_)
|
||||
| &ClauseType::Inlined(InlinedClauseType::CompareNumber(_))
|
||||
| &ClauseType::NotEq | &ClauseType::Is | &ClauseType::Eq => Some(Fixity::In),
|
||||
&ClauseType::Op(_, fixity, _) => Some(fixity),
|
||||
&BuiltInClauseType::Compare | &BuiltInClauseType::CompareTerm(_)
|
||||
| &BuiltInClauseType::NotEq | &BuiltInClauseType::Is(..) | &BuiltInClauseType::Eq
|
||||
=> Some(Fixity::In),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
|
||||
&BuiltInClauseType::Arg => clause_name!("arg"),
|
||||
&BuiltInClauseType::Compare => clause_name!("compare"),
|
||||
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
|
||||
&BuiltInClauseType::Display => clause_name!("display"),
|
||||
&BuiltInClauseType::DuplicateTerm => clause_name!("duplicate_term"),
|
||||
&BuiltInClauseType::Eq => clause_name!("=="),
|
||||
&BuiltInClauseType::Functor => clause_name!("functor"),
|
||||
&BuiltInClauseType::Ground => clause_name!("ground"),
|
||||
&BuiltInClauseType::Is(..) => clause_name!("is"),
|
||||
&BuiltInClauseType::KeySort => clause_name!("keysort"),
|
||||
&BuiltInClauseType::NotEq => clause_name!("\\=="),
|
||||
&BuiltInClauseType::Sort => clause_name!("sort"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arity(&self) -> usize {
|
||||
match self {
|
||||
&BuiltInClauseType::AcyclicTerm => 1,
|
||||
&BuiltInClauseType::Arg => 3,
|
||||
&BuiltInClauseType::Compare => 2,
|
||||
&BuiltInClauseType::CompareTerm(_) => 2,
|
||||
&BuiltInClauseType::CyclicTerm => 1,
|
||||
&BuiltInClauseType::Display => 1,
|
||||
&BuiltInClauseType::DuplicateTerm => 2,
|
||||
&BuiltInClauseType::Eq => 2,
|
||||
&BuiltInClauseType::Functor => 3,
|
||||
&BuiltInClauseType::Ground => 1,
|
||||
&BuiltInClauseType::Is(..) => 2,
|
||||
&BuiltInClauseType::KeySort => 2,
|
||||
&BuiltInClauseType::NotEq => 2,
|
||||
&BuiltInClauseType::Sort => 2,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(name: &str, arity: usize) -> Option<Self> {
|
||||
match (name, arity) {
|
||||
("acyclic_term", 1) => Some(BuiltInClauseType::AcyclicTerm),
|
||||
("arg", 3) => Some(BuiltInClauseType::Arg),
|
||||
("compare", 3) => Some(BuiltInClauseType::Compare),
|
||||
("cyclic_term", 1) => Some(BuiltInClauseType::CyclicTerm),
|
||||
("@>", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan)),
|
||||
("@<", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan)),
|
||||
("@>=", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)),
|
||||
("@=<", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)),
|
||||
("\\=@=", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::NotEqual)),
|
||||
("=@=", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::Equal)),
|
||||
("display", 1) => Some(BuiltInClauseType::Display),
|
||||
("duplicate_term", 2) => Some(BuiltInClauseType::DuplicateTerm),
|
||||
("==", 2) => Some(BuiltInClauseType::Eq),
|
||||
("functor", 3) => Some(BuiltInClauseType::Functor),
|
||||
("ground", 1) => Some(BuiltInClauseType::Ground),
|
||||
("is", 2) => Some(BuiltInClauseType::Is(temp_v!(1), ArithmeticTerm::Reg(temp_v!(2)))),
|
||||
("keysort", 2) => Some(BuiltInClauseType::KeySort),
|
||||
("\\==", 2) => Some(BuiltInClauseType::NotEq),
|
||||
("sort", 2) => Some(BuiltInClauseType::Sort),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClauseType {
|
||||
pub fn fixity(&self) -> Option<Fixity> {
|
||||
match self {
|
||||
&ClauseType::BuiltIn(ref built_in) => built_in.fixity(),
|
||||
&ClauseType::Inlined(InlinedClauseType::CompareNumber(..)) => Some(Fixity::In),
|
||||
&ClauseType::Op(_, fixity, _) => Some(fixity),
|
||||
&ClauseType::System(ref system) => system.fixity(),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&ClauseType::AcyclicTerm => clause_name!("acyclic_term"),
|
||||
&ClauseType::Arg => clause_name!("arg"),
|
||||
&ClauseType::CallN => clause_name!("call"),
|
||||
&ClauseType::CallWithInferenceLimit => clause_name!("call_with_inference_limit"),
|
||||
&ClauseType::Catch => clause_name!("catch"),
|
||||
&ClauseType::Compare => clause_name!("compare"),
|
||||
&ClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||
&ClauseType::CyclicTerm => clause_name!("cyclic_term"),
|
||||
&ClauseType::Display => clause_name!("display"),
|
||||
&ClauseType::DuplicateTerm => clause_name!("duplicate_term"),
|
||||
&ClauseType::Eq => clause_name!("=="),
|
||||
&ClauseType::Functor => clause_name!("functor"),
|
||||
&ClauseType::Ground => clause_name!("ground"),
|
||||
&ClauseType::Inlined(inlined) => clause_name!(inlined.name()),
|
||||
&ClauseType::Is => clause_name!("is"),
|
||||
&ClauseType::KeySort => clause_name!("keysort"),
|
||||
&ClauseType::NotEq => clause_name!("\\=="),
|
||||
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
|
||||
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
|
||||
&ClauseType::Op(ref name, ..) => name.clone(),
|
||||
&ClauseType::Named(ref name, ..) => name.clone(),
|
||||
&ClauseType::SetupCallCleanup => clause_name!("setup_call_cleanup"),
|
||||
&ClauseType::SkipMaxList => clause_name!("$skip_max_list"),
|
||||
&ClauseType::Sort => clause_name!("sort"),
|
||||
&ClauseType::Throw => clause_name!("throw")
|
||||
&ClauseType::System(ref system) => system.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from(name: ClauseName, arity: usize, fixity: Option<Fixity>) -> Self {
|
||||
match (name.as_str(), arity) {
|
||||
("acyclic_term", 1) => ClauseType::AcyclicTerm,
|
||||
("arg", 3) => ClauseType::Arg,
|
||||
("call", _) => ClauseType::CallN,
|
||||
("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit,
|
||||
("catch", 3) => ClauseType::Catch,
|
||||
("compare", 3) => ClauseType::Compare,
|
||||
("cyclic_term", 1) => ClauseType::CyclicTerm,
|
||||
("@>", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThan),
|
||||
("@<", 2) => ClauseType::CompareTerm(CompareTermQT::LessThan),
|
||||
("@>=", 2) => ClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual),
|
||||
("@<=", 2) => ClauseType::CompareTerm(CompareTermQT::LessThanOrEqual),
|
||||
("\\=@=", 2) => ClauseType::CompareTerm(CompareTermQT::NotEqual),
|
||||
("=@=", 2) => ClauseType::CompareTerm(CompareTermQT::Equal),
|
||||
("display", 1) => ClauseType::Display,
|
||||
("duplicate_term", 2) => ClauseType::DuplicateTerm,
|
||||
("==", 2) => ClauseType::Eq,
|
||||
("functor", 3) => ClauseType::Functor,
|
||||
("ground", 1) => ClauseType::Ground,
|
||||
("is", 2) => ClauseType::Is,
|
||||
("keysort", 2) => ClauseType::KeySort,
|
||||
("\\==", 2) => ClauseType::NotEq,
|
||||
("setup_call_cleanup", 3) => ClauseType::SetupCallCleanup,
|
||||
("$skip_max_list", 4) => ClauseType::SkipMaxList,
|
||||
("sort", 2) => ClauseType::Sort,
|
||||
("throw", 1) => ClauseType::Throw,
|
||||
_ => if let Some(fixity) = fixity {
|
||||
ClauseType::Op(name, fixity, CodeIndex::default())
|
||||
} else {
|
||||
ClauseType::Named(name, CodeIndex::default())
|
||||
}
|
||||
}
|
||||
InlinedClauseType::from(name.as_str(), arity)
|
||||
.map(ClauseType::Inlined)
|
||||
.unwrap_or_else(|| {
|
||||
BuiltInClauseType::from(name.as_str(), arity)
|
||||
.map(ClauseType::BuiltIn)
|
||||
.unwrap_or_else(|| {
|
||||
SystemClauseType::from(name.as_str(), arity)
|
||||
.map(ClauseType::System)
|
||||
.unwrap_or_else(|| {
|
||||
if let Some(fixity) = fixity {
|
||||
ClauseType::Op(name, fixity, CodeIndex::default())
|
||||
} else if name.as_str() == "call" {
|
||||
ClauseType::CallN
|
||||
} else {
|
||||
ClauseType::Named(name, CodeIndex::default())
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,18 +1043,22 @@ impl<'a> TermRef<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ChoiceInstruction {
|
||||
RetryMeElse(usize),
|
||||
TrustMe,
|
||||
TryMeElse(usize)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CutInstruction {
|
||||
Cut(RegType),
|
||||
GetLevel(RegType),
|
||||
GetLevelAndUnify(RegType),
|
||||
NeckCut
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum IndexedChoiceInstruction {
|
||||
Retry(usize),
|
||||
Trust(usize),
|
||||
@@ -1177,7 +1347,7 @@ impl Neg for Number {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum ArithmeticTerm {
|
||||
Reg(RegType),
|
||||
Interm(usize),
|
||||
@@ -1194,6 +1364,7 @@ impl ArithmeticTerm {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ArithmeticInstruction {
|
||||
Add(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Sub(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
@@ -1212,44 +1383,11 @@ pub enum ArithmeticInstruction {
|
||||
Neg(ArithmeticTerm, usize)
|
||||
}
|
||||
|
||||
pub enum BuiltInInstruction {
|
||||
CallInlined(InlinedClauseType, Vec<RegType>),
|
||||
CleanUpBlock,
|
||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||
DefaultRetryMeElse(usize),
|
||||
DefaultSetCutPoint(RegType),
|
||||
DefaultTrustMe,
|
||||
EraseBall,
|
||||
Fail,
|
||||
GetArg(bool), // last call.
|
||||
GetBall,
|
||||
GetCurrentBlock,
|
||||
GetCutPoint(RegType),
|
||||
InferenceLevel(RegType, RegType),
|
||||
InstallCleaner,
|
||||
InstallInferenceCounter(RegType, RegType, RegType),
|
||||
InstallNewBlock,
|
||||
InternalCallN,
|
||||
RemoveCallPolicyCheck,
|
||||
RemoveInferenceCounter(RegType, RegType),
|
||||
ResetBlock,
|
||||
RestoreCutPolicy,
|
||||
SetBall,
|
||||
SetCutPoint(RegType),
|
||||
Succeed,
|
||||
Unify,
|
||||
UnwindStack
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ControlInstruction {
|
||||
Allocate(usize), // num_frames.
|
||||
CallClause(ClauseType, usize, usize, bool), // name, arity, perm_vars after threshold, last call.
|
||||
CheckCpExecute,
|
||||
Deallocate,
|
||||
GetCleanerCall,
|
||||
Goto(usize, usize, bool), // p, arity, last call.
|
||||
IsClause(bool, RegType, ArithmeticTerm), // last call, register of var, term.
|
||||
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
|
||||
Proceed
|
||||
}
|
||||
@@ -1258,19 +1396,17 @@ impl ControlInstruction {
|
||||
pub fn is_jump_instr(&self) -> bool {
|
||||
match self {
|
||||
&ControlInstruction::CallClause(..) => true,
|
||||
&ControlInstruction::GetCleanerCall => true,
|
||||
&ControlInstruction::Goto(..) => true,
|
||||
&ControlInstruction::IsClause(..) => true,
|
||||
&ControlInstruction::JmpBy(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum IndexingInstruction {
|
||||
SwitchOnTerm(usize, usize, usize, usize),
|
||||
SwitchOnConstant(usize, HashMap<Constant, usize>),
|
||||
SwitchOnStructure(usize, HashMap<(ClauseName, usize), usize>)
|
||||
SwitchOnConstant(usize, Rc<HashMap<Constant, usize>>),
|
||||
SwitchOnStructure(usize, Rc<HashMap<(ClauseName, usize), usize>>)
|
||||
}
|
||||
|
||||
impl From<IndexingInstruction> for Line {
|
||||
@@ -1279,6 +1415,7 @@ impl From<IndexingInstruction> for Line {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FactInstruction {
|
||||
GetConstant(Level, Constant, RegType),
|
||||
GetList(Level, RegType),
|
||||
@@ -1292,6 +1429,7 @@ pub enum FactInstruction {
|
||||
UnifyVoid(usize)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum QueryInstruction {
|
||||
GetVariable(RegType, usize),
|
||||
PutConstant(Level, Constant, RegType),
|
||||
@@ -1311,9 +1449,9 @@ pub type CompiledFact = Vec<FactInstruction>;
|
||||
|
||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Line {
|
||||
Arithmetic(ArithmeticInstruction),
|
||||
BuiltIn(BuiltInInstruction),
|
||||
Choice(ChoiceInstruction),
|
||||
Control(ControlInstruction),
|
||||
Cut(CutInstruction),
|
||||
@@ -1338,6 +1476,38 @@ pub enum Addr {
|
||||
Str(usize)
|
||||
}
|
||||
|
||||
impl PartialEq<Ref> for Addr {
|
||||
fn eq(&self, r: &Ref) -> bool {
|
||||
self.as_var() == Some(*r)
|
||||
}
|
||||
}
|
||||
|
||||
// for use in MachineState::bind.
|
||||
impl PartialOrd<Ref> for Addr {
|
||||
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
||||
match self {
|
||||
&Addr::StackCell(fr, sc) =>
|
||||
match *r {
|
||||
Ref::HeapCell(_) => Some(Ordering::Greater),
|
||||
Ref::StackCell(fr1, sc1) =>
|
||||
if fr1 < fr || (fr1 == fr && sc1 < sc) {
|
||||
Some(Ordering::Greater)
|
||||
} else if fr1 == fr && sc1 == sc {
|
||||
Some(Ordering::Equal)
|
||||
} else {
|
||||
Some(Ordering::Less)
|
||||
}
|
||||
},
|
||||
&Addr::HeapCell(h) =>
|
||||
match r {
|
||||
Ref::StackCell(..) => Some(Ordering::Less),
|
||||
Ref::HeapCell(h1) => h.partial_cmp(h1)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Addr {
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
@@ -1356,7 +1526,7 @@ impl Addr {
|
||||
|
||||
pub fn is_protected(&self, e: usize) -> bool {
|
||||
match self {
|
||||
&Addr::StackCell(fr, _) if fr > e => false,
|
||||
&Addr::StackCell(addr, _) if addr >= e => false,
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
@@ -1403,6 +1573,15 @@ pub enum Ref {
|
||||
StackCell(usize, usize)
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
pub fn as_addr(self) -> Addr {
|
||||
match self {
|
||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum HeapCellValue {
|
||||
Addr(Addr),
|
||||
@@ -1449,15 +1628,32 @@ impl From<(usize, ClauseName)> for CodeIndex {
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CodePtr {
|
||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||
CallN(usize, LocalCodePtr), // arity, local.
|
||||
Local(LocalCodePtr)
|
||||
}
|
||||
|
||||
impl CodePtr {
|
||||
pub fn local(&self) -> LocalCodePtr {
|
||||
match self {
|
||||
&CodePtr::BuiltInClause(_, ref local)
|
||||
| &CodePtr::CallN(_, ref local)
|
||||
| &CodePtr::Local(ref local) => local.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum LocalCodePtr {
|
||||
DirEntry(usize, ClauseName), // offset, resident module name.
|
||||
TopLevel(usize, usize) // chunk_num, offset.
|
||||
}
|
||||
|
||||
impl CodePtr {
|
||||
pub fn module_name(&self) -> ClauseName {
|
||||
match self {
|
||||
&CodePtr::DirEntry(_, ref name) => name.clone(),
|
||||
_ => ClauseName::BuiltIn("user")
|
||||
impl LocalCodePtr {
|
||||
pub fn assign_if_local(&mut self, cp: CodePtr) {
|
||||
match cp {
|
||||
CodePtr::Local(local) => *self = local,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1465,11 +1661,20 @@ impl CodePtr {
|
||||
impl PartialOrd<CodePtr> for CodePtr {
|
||||
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(&CodePtr::DirEntry(p1, _), &CodePtr::DirEntry(p2, _)) =>
|
||||
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2),
|
||||
_ => Some(Ordering::Greater)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<LocalCodePtr> for LocalCodePtr {
|
||||
fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
|
||||
match (self, other) {
|
||||
(&LocalCodePtr::DirEntry(p1, _), &LocalCodePtr::DirEntry(p2, _)) =>
|
||||
p1.partial_cmp(&p2),
|
||||
(&CodePtr::DirEntry(..), &CodePtr::TopLevel(_, _)) =>
|
||||
(&LocalCodePtr::DirEntry(..), &LocalCodePtr::TopLevel(_, _)) =>
|
||||
Some(Ordering::Less),
|
||||
(&CodePtr::TopLevel(_, p1), &CodePtr::TopLevel(_, ref p2)) =>
|
||||
(&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) =>
|
||||
p1.partial_cmp(p2),
|
||||
_ => Some(Ordering::Greater)
|
||||
}
|
||||
@@ -1478,7 +1683,33 @@ impl PartialOrd<CodePtr> for CodePtr {
|
||||
|
||||
impl Default for CodePtr {
|
||||
fn default() -> Self {
|
||||
CodePtr::TopLevel(0, 0)
|
||||
CodePtr::Local(LocalCodePtr::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LocalCodePtr {
|
||||
fn default() -> Self {
|
||||
LocalCodePtr::TopLevel(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for LocalCodePtr {
|
||||
type Output = LocalCodePtr;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p, name) => LocalCodePtr::DirEntry(p + rhs, name),
|
||||
LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<usize> for LocalCodePtr {
|
||||
fn add_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
&mut LocalCodePtr::DirEntry(ref mut p, _) |
|
||||
&mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1487,8 +1718,8 @@ impl Add<usize> for CodePtr {
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
CodePtr::DirEntry(p, name) => CodePtr::DirEntry(p + rhs, name),
|
||||
CodePtr::TopLevel(cn, p) => CodePtr::TopLevel(cn, p + rhs)
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1496,8 +1727,8 @@ impl Add<usize> for CodePtr {
|
||||
impl AddAssign<usize> for CodePtr {
|
||||
fn add_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
&mut CodePtr::DirEntry(ref mut p, _) |
|
||||
&mut CodePtr::TopLevel(_, ref mut p) => *p += rhs
|
||||
&mut CodePtr::Local(ref mut local) => *local += rhs,
|
||||
_ => *self = CodePtr::Local(self.local() + rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,931 +0,0 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::num::bigint::{BigInt};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
// from 7.12.2 b) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ValidType {
|
||||
Atom,
|
||||
Atomic,
|
||||
Byte,
|
||||
Callable,
|
||||
Character,
|
||||
Compound,
|
||||
Evaluable,
|
||||
InByte,
|
||||
InCharacter,
|
||||
Integer,
|
||||
List,
|
||||
Number,
|
||||
Pair,
|
||||
PredicateIndicator,
|
||||
Variable
|
||||
}
|
||||
|
||||
impl ValidType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ValidType::Atom => "atom",
|
||||
ValidType::Atomic => "atomic",
|
||||
ValidType::Byte => "byte",
|
||||
ValidType::Callable => "callable",
|
||||
ValidType::Character => "character",
|
||||
ValidType::Compound => "compound",
|
||||
ValidType::Evaluable => "evaluable",
|
||||
ValidType::InByte => "in_byte",
|
||||
ValidType::InCharacter => "in_character",
|
||||
ValidType::Integer => "integer",
|
||||
ValidType::List => "list",
|
||||
ValidType::Number => "number",
|
||||
ValidType::Pair => "pair",
|
||||
ValidType::PredicateIndicator => "predicate_indicator",
|
||||
ValidType::Variable => "variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 f) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RepFlag {
|
||||
Character,
|
||||
CharacterCode,
|
||||
InCharacterCode,
|
||||
MaxArity,
|
||||
MaxInteger,
|
||||
MinInteger
|
||||
}
|
||||
|
||||
impl RepFlag {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
RepFlag::Character => "character",
|
||||
RepFlag::CharacterCode => "character_code",
|
||||
RepFlag::InCharacterCode => "in_character_code",
|
||||
RepFlag::MaxArity => "max_arity",
|
||||
RepFlag::MaxInteger => "max_integer",
|
||||
RepFlag::MinInteger => "min_integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 g) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum EvalError {
|
||||
FloatOverflow,
|
||||
IntOverflow,
|
||||
Undefined,
|
||||
Underflow,
|
||||
ZeroDivisor
|
||||
}
|
||||
|
||||
impl EvalError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
EvalError::FloatOverflow => "float_overflow",
|
||||
EvalError::IntOverflow => "int_overflow",
|
||||
EvalError::Undefined => "undefined",
|
||||
EvalError::Underflow => "underflow",
|
||||
EvalError::ZeroDivisor => "zero_divisor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_builtins() -> Code {
|
||||
vec![internal_call_n!(), // callN/N, 0.
|
||||
is_atomic!(temp_v!(1)), // atomic/1, 1.
|
||||
proceed!(),
|
||||
is_var!(temp_v!(1)), // var/1, 3.
|
||||
proceed!(),
|
||||
allocate!(4), // catch/3, 5.
|
||||
fact![get_var_in_fact!(perm_v!(2), 1),
|
||||
get_var_in_fact!(perm_v!(3), 2),
|
||||
get_var_in_fact!(perm_v!(1), 3)],
|
||||
query![put_var!(perm_v!(4), 1)],
|
||||
get_current_block!(),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_value!(perm_v!(1), 3),
|
||||
put_unsafe_value!(4, 4)],
|
||||
deallocate!(),
|
||||
goto_execute!(12, 4), // goto catch/4.
|
||||
try_me_else!(10), // catch/4, 12.
|
||||
allocate!(3),
|
||||
fact![get_var_in_fact!(perm_v!(3), 1),
|
||||
get_var_in_fact!(perm_v!(2), 4)],
|
||||
query![put_var!(perm_v!(1), 1)],
|
||||
install_new_block!(),
|
||||
query![put_value!(perm_v!(3), 1)],
|
||||
call_n!(1),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_unsafe_value!(1, 2)],
|
||||
deallocate!(),
|
||||
goto_execute!(44, 2), //21: goto end_block/2.
|
||||
default_trust_me!(),
|
||||
allocate!(3),
|
||||
fact![get_var_in_fact!(perm_v!(2), 2),
|
||||
get_var_in_fact!(perm_v!(1), 3)],
|
||||
query![get_var_in_query!(temp_v!(2), 1),
|
||||
put_value!(temp_v!(4), 1)],
|
||||
reset_block!(),
|
||||
query![put_var!(perm_v!(3), 1)],
|
||||
get_ball!(),
|
||||
query![put_unsafe_value!(3, 1),
|
||||
put_value!(perm_v!(2), 2),
|
||||
put_value!(perm_v!(1), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(32, 2), // goto handle_ball/2.
|
||||
try_me_else!(10), // handle_ball/2, 32.
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(2), 3)],
|
||||
unify!(),
|
||||
cut!(perm_v!(1)),
|
||||
erase_ball!(),
|
||||
query![put_value!(perm_v!(2), 1)],
|
||||
deallocate!(),
|
||||
execute_n!(1),
|
||||
default_trust_me!(),
|
||||
unwind_stack!(),
|
||||
try_me_else!(9), // end_block/2, 44.
|
||||
allocate!(1),
|
||||
fact![get_var_in_fact!(perm_v!(1), 1)],
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
clean_up_block!(),
|
||||
query![put_value!(perm_v!(1), 1)],
|
||||
deallocate!(),
|
||||
reset_block!(),
|
||||
proceed!(),
|
||||
default_trust_me!(), // 53.
|
||||
allocate!(0),
|
||||
query![get_var_in_query!(temp_v!(3), 1),
|
||||
put_value!(temp_v!(2), 1)],
|
||||
reset_block!(),
|
||||
deallocate!(),
|
||||
goto_execute!(61, 0),
|
||||
set_ball!(), // throw/1, 59.
|
||||
unwind_stack!(),
|
||||
fail!(), // false/0, 61.
|
||||
try_me_else!(7), // not/1, 62.
|
||||
allocate!(1),
|
||||
get_level!(perm_v!(1)),
|
||||
call_n!(1),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(61, 0),
|
||||
trust_me!(),
|
||||
proceed!(),
|
||||
duplicate_term!(), // duplicate_term/2, 71.
|
||||
proceed!(),
|
||||
fact![get_value!(temp_v!(1), 2)], // =/2, 73.
|
||||
proceed!(),
|
||||
proceed!(), // true/0, 75.
|
||||
get_cp!(temp_v!(3)), // ','/2, 76.
|
||||
try_me_else!(18), // ','/3, 77.
|
||||
switch_on_term!(4, 1, 0, 0),
|
||||
indexed_try!(4),
|
||||
retry!(7),
|
||||
trust!(10),
|
||||
try_me_else!(4),
|
||||
fact![get_constant!(atom!("!"), temp_v!(1)),
|
||||
get_structure!(",", 2, temp_v!(2), Some(infix!())),
|
||||
unify_variable!(temp_v!(1)),
|
||||
unify_variable!(temp_v!(2))],
|
||||
set_cp!(temp_v!(3)),
|
||||
goto_execute!(77, 3),
|
||||
retry_me_else!(4),
|
||||
fact![get_constant!(atom!("!"), temp_v!(1)),
|
||||
get_constant!(atom!("!"), temp_v!(2))],
|
||||
set_cp!(temp_v!(3)),
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
fact![get_constant!(atom!("!"), temp_v!(1))],
|
||||
set_cp!(temp_v!(3)),
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
execute_n!(1),
|
||||
retry_me_else!(8), // 95.
|
||||
allocate!(3),
|
||||
fact![get_structure!(",", 2, temp_v!(2), Some(infix!())),
|
||||
unify_variable!(perm_v!(2)),
|
||||
unify_variable!(perm_v!(1)),
|
||||
get_var_in_fact!(perm_v!(3), 3)],
|
||||
neck_cut!(),
|
||||
call_n!(1),
|
||||
query![put_unsafe_value!(2, 1),
|
||||
put_unsafe_value!(1, 2),
|
||||
put_value!(perm_v!(3), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(77, 3),
|
||||
retry_me_else!(10),
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(2)),
|
||||
fact![get_constant!(atom!("!"), temp_v!(2)),
|
||||
get_var_in_fact!(perm_v!(1), 3)],
|
||||
neck_cut!(),
|
||||
call_n!(1),
|
||||
query![put_value!(perm_v!(1), 1)],
|
||||
set_cp!(temp_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
allocate!(1),
|
||||
fact![get_var_in_fact!(perm_v!(1), 2)],
|
||||
call_n!(1),
|
||||
query![put_value!(perm_v!(1), 1)],
|
||||
deallocate!(),
|
||||
execute_n!(1),
|
||||
get_cp!(temp_v!(3)), // ';'/2, 120.
|
||||
try_me_else!(16), // ';'/3, 121.
|
||||
switch_on_term!(0, 12, 0, 1), // Fail on variable input.
|
||||
indexed_try!(2),
|
||||
trust!(5),
|
||||
fact![get_structure!("->", 2, temp_v!(1), Some(infix!())),
|
||||
unify_variable!(temp_v!(1)),
|
||||
unify_variable!(temp_v!(4))],
|
||||
query![put_value!(temp_v!(4), 2)],
|
||||
goto_execute!(147, 3), // goto '->'/3.
|
||||
retry_me_else!(5),
|
||||
fact![get_structure!("->", 2, temp_v!(1), Some(infix!())),
|
||||
unify_void!(2)],
|
||||
set_cp!(temp_v!(3)),
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
execute_n!(1),
|
||||
retry_me_else!(4),
|
||||
fact![get_constant!(atom!("!"), temp_v!(1))],
|
||||
set_cp!(temp_v!(3)),
|
||||
proceed!(),
|
||||
retry_me_else!(4),
|
||||
fact![get_constant!(atom!("!"), temp_v!(2))],
|
||||
set_cp!(temp_v!(3)),
|
||||
proceed!(),
|
||||
retry_me_else!(2),
|
||||
execute_n!(1),
|
||||
trust_me!(),
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
execute_n!(1),
|
||||
get_cp!(temp_v!(3)), // '->'/2, 146.
|
||||
try_me_else!(7), // '->'/3, 147.
|
||||
allocate!(1),
|
||||
fact![get_constant!(atom!("!"), temp_v!(2)),
|
||||
get_var_in_fact!(perm_v!(1), 3)],
|
||||
call_n!(1),
|
||||
set_cp!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
allocate!(2),
|
||||
fact![get_var_in_fact!(perm_v!(1), 2),
|
||||
get_var_in_fact!(perm_v!(2), 3)],
|
||||
call_n!(1),
|
||||
set_cp!(perm_v!(2)),
|
||||
query![put_unsafe_value!(1, 1)],
|
||||
deallocate!(),
|
||||
execute_n!(1),
|
||||
functor_execute!(), // functor/3, 162.
|
||||
is_integer!(temp_v!(1)), // integer/1, 163.
|
||||
proceed!(),
|
||||
get_arg_execute!(), // get_arg/3, 165.
|
||||
try_me_else!(10), // arg/3, 166.
|
||||
allocate!(4),
|
||||
fact![get_var_in_fact!(perm_v!(1), 1),
|
||||
get_var_in_fact!(perm_v!(2), 2),
|
||||
get_var_in_fact!(perm_v!(4), 3)],
|
||||
is_var!(perm_v!(1)),
|
||||
neck_cut!(),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_var!(temp_v!(4), 2),
|
||||
put_var!(perm_v!(3), 3)],
|
||||
functor_call!(),
|
||||
query![put_value!(perm_v!(1), 1),
|
||||
put_constant!(Level::Shallow, integer!(1), temp_v!(2)),
|
||||
put_unsafe_value!(3, 3),
|
||||
put_value!(perm_v!(2), 4),
|
||||
put_value!(perm_v!(4), 5)],
|
||||
deallocate!(),
|
||||
goto_execute!(189, 5), // goto arg_/5, 175.
|
||||
retry_me_else!(10),
|
||||
allocate!(3),
|
||||
fact![get_var_in_fact!(perm_v!(1), 1),
|
||||
get_var_in_fact!(perm_v!(2), 2),
|
||||
get_var_in_fact!(perm_v!(3), 3)],
|
||||
is_integer!(perm_v!(1)),
|
||||
neck_cut!(),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_var!(temp_v!(4), 2),
|
||||
put_var!(temp_v!(3), 3)],
|
||||
functor_call!(),
|
||||
query![put_value!(perm_v!(1), 1),
|
||||
put_value!(perm_v!(2), 2),
|
||||
put_value!(perm_v!(3), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(165, 3), // goto get_arg/3, 185.
|
||||
trust_me!(),
|
||||
query![get_var_in_query!(temp_v!(4), 1),
|
||||
put_structure!("type_error", 2, temp_v!(2), None),
|
||||
set_constant!(atom!(ValidType::Integer.as_str())),
|
||||
set_value!(temp_v!(4)),
|
||||
put_structure!("error", 2, temp_v!(1), None),
|
||||
set_value!(temp_v!(2)),
|
||||
set_void!(1)],
|
||||
goto_execute!(59, 1), // goto throw/1.
|
||||
try_me_else!(5), // arg_/5, 189.
|
||||
fact![get_value!(temp_v!(1), 2),
|
||||
get_value!(temp_v!(1), 3)],
|
||||
neck_cut!(),
|
||||
query![put_value!(temp_v!(4), 2),
|
||||
put_value!(temp_v!(5), 3)],
|
||||
goto_execute!(165, 3), // goto get_arg/3.
|
||||
retry_me_else!(4),
|
||||
fact![get_value!(temp_v!(1), 2)],
|
||||
query![put_value!(temp_v!(4), 2),
|
||||
get_var_in_query!(temp_v!(6), 3),
|
||||
put_value!(temp_v!(5), 3)],
|
||||
goto_execute!(165, 3), // goto get_arg/3, 197.
|
||||
trust_me!(),
|
||||
allocate!(5),
|
||||
fact![get_var_in_fact!(perm_v!(2), 1),
|
||||
get_var_in_fact!(perm_v!(4), 3),
|
||||
get_var_in_fact!(perm_v!(3), 4),
|
||||
get_var_in_fact!(perm_v!(5), 5)],
|
||||
compare_number_instr!(CompareNumberQT::LessThan,
|
||||
ArithmeticTerm::Reg(temp_v!(2)),
|
||||
ArithmeticTerm::Reg(perm_v!(4))),
|
||||
add!(ArithmeticTerm::Reg(temp_v!(2)),
|
||||
ArithmeticTerm::Number(rc_integer!(1)),
|
||||
1),
|
||||
query![put_var!(perm_v!(1), 1)],
|
||||
is_call!(perm_v!(1), interm!(1)),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_unsafe_value!(1, 2),
|
||||
put_value!(perm_v!(4), 3),
|
||||
put_value!(perm_v!(3), 4),
|
||||
put_value!(perm_v!(5), 5)],
|
||||
deallocate!(),
|
||||
goto_execute!(189, 5), // goto arg_/5, 207.
|
||||
display!(), // display/1, 208.
|
||||
proceed!(),
|
||||
dynamic_is!(), // is/2, 210.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_gt!()), // >/2, 212.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_lt!()), // </2, 214.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_gte!()), // >=/2, 216.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_lte!()), // =</2, 218.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_ne!()), // =\=, 220.
|
||||
proceed!(),
|
||||
dynamic_num_test!(cmp_eq!()), // =:=, 222.
|
||||
proceed!(),
|
||||
try_me_else!(5), // =.., 224.
|
||||
fact![get_var_in_fact!(temp_v!(3), 1),
|
||||
get_list!(Level::Shallow, temp_v!(2)),
|
||||
unify_value!(temp_v!(3)),
|
||||
unify_constant!(Constant::EmptyList)],
|
||||
is_atomic!(temp_v!(3)),
|
||||
neck_cut!(),
|
||||
proceed!(),
|
||||
retry_me_else!(11),
|
||||
allocate!(4),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(3), 1),
|
||||
get_list!(Level::Shallow, temp_v!(2)),
|
||||
unify_variable!(temp_v!(2)),
|
||||
unify_variable!(perm_v!(4))],
|
||||
is_var!(perm_v!(4)),
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_var!(perm_v!(2), 3)],
|
||||
functor_call!(),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_unsafe_value!(4, 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_constant!(Level::Shallow, integer!(1), temp_v!(3)),
|
||||
put_unsafe_value!(2, 4)],
|
||||
deallocate!(),
|
||||
goto_execute!(252, 4), // goto get_args/4, 239.
|
||||
trust_me!(),
|
||||
allocate!(5),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(3), 1),
|
||||
get_list!(Level::Shallow, temp_v!(2)),
|
||||
unify_variable!(perm_v!(5)),
|
||||
unify_variable!(perm_v!(4))],
|
||||
query![put_value!(perm_v!(4), 1),
|
||||
put_var!(perm_v!(2), 2)],
|
||||
goto_call!(277, 2), // goto length/2, 245.
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_value!(perm_v!(5), 2),
|
||||
put_value!(perm_v!(2), 3)],
|
||||
functor_call!(),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_unsafe_value!(4, 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_constant!(Level::Shallow, integer!(1), temp_v!(3)),
|
||||
put_unsafe_value!(2, 4)],
|
||||
deallocate!(),
|
||||
goto_execute!(252, 4), // goto get_args/4, 251.
|
||||
try_me_else!(5), // get_args/4, 252.
|
||||
fact![get_var_in_fact!(temp_v!(5), 1),
|
||||
get_constant!(integer!(0), temp_v!(4))],
|
||||
neck_cut!(),
|
||||
query![put_value!(temp_v!(5), 1),
|
||||
put_constant!(Level::Shallow, Constant::EmptyList, temp_v!(2))],
|
||||
goto_execute!(73, 2), // goto =/2, 256.
|
||||
trust_me!(),
|
||||
switch_on_term!(3, 0, 1, 0),
|
||||
indexed_try!(3),
|
||||
trust!(7),
|
||||
try_me_else!(5),
|
||||
fact![get_list!(Level::Shallow, temp_v!(1)),
|
||||
unify_variable!(temp_v!(5)),
|
||||
unify_constant!(Constant::EmptyList),
|
||||
get_var_in_fact!(temp_v!(6), 2),
|
||||
get_var_in_fact!(temp_v!(1), 3),
|
||||
get_value!(temp_v!(1), 4)],
|
||||
neck_cut!(),
|
||||
query![put_value!(temp_v!(6), 2),
|
||||
put_value!(temp_v!(5), 3)],
|
||||
get_arg_execute!(),
|
||||
trust_me!(),
|
||||
allocate!(5),
|
||||
fact![get_list!(Level::Shallow, temp_v!(1)),
|
||||
unify_variable!(temp_v!(5)),
|
||||
unify_variable!(perm_v!(4)),
|
||||
get_var_in_fact!(perm_v!(3), 2),
|
||||
get_var_in_fact!(perm_v!(5), 3),
|
||||
get_var_in_fact!(perm_v!(1), 4)],
|
||||
query![put_value!(perm_v!(5), 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_value!(temp_v!(5), 3)],
|
||||
get_arg_call!(),
|
||||
add!(ArithmeticTerm::Reg(perm_v!(5)),
|
||||
ArithmeticTerm::Number(rc_integer!(1)),
|
||||
1),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
is_call!(perm_v!(2), ArithmeticTerm::Interm(1)),
|
||||
query![put_unsafe_value!(4, 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_unsafe_value!(2, 3),
|
||||
put_value!(perm_v!(1), 4)],
|
||||
deallocate!(),
|
||||
goto_execute!(252, 4), // goto get_args/4, 276.
|
||||
try_me_else!(6), // length/2, 277.
|
||||
fact![get_var_in_fact!(temp_v!(4), 1),
|
||||
get_var_in_fact!(temp_v!(3), 2)],
|
||||
is_var!(temp_v!(3)),
|
||||
neck_cut!(),
|
||||
query![put_value!(temp_v!(4), 1),
|
||||
put_constant!(Level::Shallow, integer!(0), temp_v!(2))],
|
||||
goto_execute!(297, 3), // goto length/3, 282.
|
||||
retry_me_else!(10),
|
||||
allocate!(1),
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(temp_v!(4), 1),
|
||||
get_var_in_fact!(temp_v!(3), 2)],
|
||||
is_integer!(temp_v!(3)),
|
||||
query![put_value!(temp_v!(4), 1),
|
||||
put_constant!(Level::Shallow, integer!(0), temp_v!(2))],
|
||||
goto_call!(297, 3), // goto length/3, 289.
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
fact![get_var_in_fact!(temp_v!(3), 1),
|
||||
get_var_in_fact!(temp_v!(4), 2)],
|
||||
query![put_structure!("type_error", 2, temp_v!(1), None),
|
||||
set_constant!(atom!("integer_expected")),
|
||||
set_value!(temp_v!(4))],
|
||||
goto_execute!(59, 1), // goto throw/1, 296.
|
||||
switch_on_term!(1, 2, 5, 0), // length/3, 297.
|
||||
try_me_else!(3),
|
||||
fact![get_constant!(Constant::EmptyList, temp_v!(1)),
|
||||
get_var_in_fact!(temp_v!(4), 2),
|
||||
get_value!(temp_v!(4), 3)],
|
||||
proceed!(),
|
||||
trust_me!(),
|
||||
allocate!(3),
|
||||
fact![get_list!(Level::Shallow, temp_v!(1)),
|
||||
unify_void!(1),
|
||||
unify_variable!(perm_v!(1)),
|
||||
get_var_in_fact!(temp_v!(4), 2),
|
||||
get_var_in_fact!(perm_v!(3), 3)],
|
||||
add!(ArithmeticTerm::Reg(temp_v!(4)),
|
||||
ArithmeticTerm::Number(rc_integer!(1)),
|
||||
1),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
is_call!(perm_v!(2), ArithmeticTerm::Interm(1)),
|
||||
query![put_unsafe_value!(1, 1),
|
||||
put_unsafe_value!(2, 2),
|
||||
put_value!(perm_v!(3), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(297, 3), // goto length/3, 309.
|
||||
allocate!(4), // setup_call_cleanup/3, 310.
|
||||
get_level!(perm_v!(1)),
|
||||
fact![get_var_in_fact!(perm_v!(2), 2),
|
||||
get_var_in_fact!(perm_v!(3), 3)],
|
||||
call_n!(1),
|
||||
cut!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(4), 1)],
|
||||
get_current_block!(),
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_unsafe_value!(4, 2),
|
||||
put_value!(perm_v!(2), 3)],
|
||||
deallocate!(),
|
||||
jmp_execute!(3, 1, 0),
|
||||
try_me_else!(5), // 320.
|
||||
is_var!(temp_v!(1)),
|
||||
neck_cut!(),
|
||||
query![put_constant!(Level::Shallow,
|
||||
atom!("instantiation_error"),
|
||||
temp_v!(1))],
|
||||
goto_execute!(59, 1),
|
||||
default_trust_me!(),
|
||||
query![get_var_in_query!(temp_v!(4), 2),
|
||||
put_value!(temp_v!(3), 2),
|
||||
get_var_in_query!(temp_v!(5), 3),
|
||||
put_value!(temp_v!(4), 3)],
|
||||
goto_execute!(328, 3),
|
||||
try_me_else!(13), // sgc_helper/3, 328.
|
||||
allocate!(4),
|
||||
fact![get_var_in_fact!(perm_v!(4), 1),
|
||||
get_var_in_fact!(perm_v!(3), 2),
|
||||
get_var_in_fact!(perm_v!(2), 3)],
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_value!(perm_v!(4), 1)],
|
||||
install_cleaner!(),
|
||||
query![put_var!(temp_v!(2), 1)],
|
||||
install_new_block!(),
|
||||
query![put_value!(perm_v!(3), 1)],
|
||||
call_n!(1),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_value!(perm_v!(1), 2)],
|
||||
deallocate!(),
|
||||
check_cp_execute!(),
|
||||
default_retry_me_else!(12),
|
||||
allocate!(2),
|
||||
query![put_value!(temp_v!(3), 1)],
|
||||
reset_block!(),
|
||||
query![put_var!(perm_v!(1), 1)],
|
||||
get_ball!(),
|
||||
get_level!(perm_v!(2)),
|
||||
default_set_cp!(perm_v!(2)),
|
||||
goto_call!(358, 0), // goto run_cleaners_with_handling/0, 349.
|
||||
query![put_unsafe_value!(1, 1)],
|
||||
deallocate!(),
|
||||
goto_execute!(59, 1), // goto throw/1, 59.
|
||||
default_trust_me!(),
|
||||
allocate!(0),
|
||||
goto_call!(370, 0), // goto run_cleaners_without_handling/0, 355.
|
||||
deallocate!(),
|
||||
fail!(),
|
||||
try_me_else!(10), // run_cleaners_with_handling/0, 358.
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
get_cleaner_call!(),
|
||||
query![put_value!(perm_v!(2), 1),
|
||||
put_var!(temp_v!(4), 2),
|
||||
put_constant!(Level::Shallow, atom!("true"), temp_v!(3))],
|
||||
goto_call!(5, 3), // goto catch/3, 5.
|
||||
default_set_cp!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(358, 0), // goto run_cleaners_with_handling/0, 367.
|
||||
default_trust_me!(),
|
||||
goto_execute!(398, 0), // goto restore_cut_points/0, 369.
|
||||
try_me_else!(10), // run_cleaners_without_handling/0, 370.
|
||||
allocate!(2),
|
||||
get_level!(perm_v!(1)),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
get_cleaner_call!(),
|
||||
query![put_value!(perm_v!(2), 1)],
|
||||
call_n!(1),
|
||||
default_set_cp!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
goto_execute!(370, 0), // goto run_cleaners_without_handling/0, 379.
|
||||
default_trust_me!(),
|
||||
goto_execute!(398, 0), // goto restore_cut_points/0, 381.
|
||||
allocate!(1), // sgc_on_success/2, 382.
|
||||
fact![get_var_in_fact!(perm_v!(1), 2)],
|
||||
reset_block!(),
|
||||
cut!(perm_v!(1)),
|
||||
deallocate!(),
|
||||
proceed!(),
|
||||
is_compound!(temp_v!(1)), // compound/1, 388.
|
||||
proceed!(),
|
||||
is_rational!(temp_v!(1)), // rational/1, 390.
|
||||
proceed!(),
|
||||
is_string!(temp_v!(1)), // string/1, 392.
|
||||
proceed!(),
|
||||
is_float!(temp_v!(1)), // float/1, 394.
|
||||
proceed!(),
|
||||
is_nonvar!(temp_v!(1)), // nonvar/1, 396.
|
||||
proceed!(),
|
||||
restore_cut_policy!(), // restore_cut_policy/0, 398.
|
||||
proceed!(),
|
||||
ground_execute!(), // ground/1, 400.
|
||||
eq_execute!(), // (==)/2, 401.
|
||||
not_eq_execute!(), // (\==)/2, 402.
|
||||
compare_term_execute!(term_cmp_gte!()), // (@>=)/2, 403.
|
||||
compare_term_execute!(term_cmp_lte!()), // (@=<)/2, 404.
|
||||
compare_term_execute!(term_cmp_gt!()), // (@>)/2, 405.
|
||||
compare_term_execute!(term_cmp_lt!()), // (@<)/2, 406.
|
||||
compare_term_execute!(term_cmp_eq!()), // (=@=)/2, 407.
|
||||
compare_term_execute!(term_cmp_ne!()), // (\=@=)/2, 408.
|
||||
allocate!(5), // call_with_inference_limit/3, 409.
|
||||
fact![get_var_in_fact!(perm_v!(4), 1),
|
||||
get_var_in_fact!(perm_v!(3), 2),
|
||||
get_var_in_fact!(perm_v!(2), 3)],
|
||||
query![put_var!(perm_v!(5), 1)],
|
||||
get_current_block!(),
|
||||
get_cp!(perm_v!(1)),
|
||||
query![put_value!(perm_v!(4), 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_value!(perm_v!(2), 3),
|
||||
put_value!(perm_v!(5), 4),
|
||||
put_value!(perm_v!(1), 5)],
|
||||
goto_call!(420, 5), // goto call_with_inference_limit/5, 415
|
||||
query![put_value!(perm_v!(1), 1)],
|
||||
deallocate!(),
|
||||
remove_call_policy_check!(),
|
||||
proceed!(),
|
||||
try_me_else!(19), // call_with_inference_limit/5, 420.
|
||||
allocate!(9),
|
||||
fact![get_var_in_fact!(perm_v!(9), 1),
|
||||
get_var_in_fact!(perm_v!(5), 2),
|
||||
get_var_in_fact!(perm_v!(8), 3),
|
||||
get_var_in_fact!(perm_v!(3), 4),
|
||||
get_var_in_fact!(perm_v!(4), 5)],
|
||||
query![put_var!(perm_v!(1), 1)],
|
||||
install_new_block!(),
|
||||
query![put_var!(perm_v!(7), 3)],
|
||||
install_inference_counter!(perm_v!(4), perm_v!(5), perm_v!(7)),
|
||||
query![put_value!(perm_v!(9), 1)],
|
||||
call_n!(1),
|
||||
inference_level!(perm_v!(8), perm_v!(4)),
|
||||
query![put_var!(perm_v!(6), 2)],
|
||||
remove_inference_counter!(perm_v!(4), perm_v!(6)),
|
||||
sub!(ArithmeticTerm::Reg(perm_v!(6)),
|
||||
ArithmeticTerm::Reg(perm_v!(7)),
|
||||
1),
|
||||
sub!(ArithmeticTerm::Reg(perm_v!(5)),
|
||||
ArithmeticTerm::Interm(1),
|
||||
1),
|
||||
query![put_var!(perm_v!(2), 1)],
|
||||
is_call!(temp_v!(1), ArithmeticTerm::Interm(1)),
|
||||
query![put_value!(perm_v!(4), 1),
|
||||
put_value!(perm_v!(3), 2),
|
||||
put_value!(perm_v!(1), 3),
|
||||
put_value!(perm_v!(2), 4)],
|
||||
deallocate!(),
|
||||
goto_execute!(468, 4), // goto end_block/4, 468
|
||||
default_trust_me!(), // 439
|
||||
allocate!(3),
|
||||
fact![get_var_in_fact!(perm_v!(1), 3),
|
||||
get_var_in_fact!(perm_v!(3), 5)],
|
||||
query![put_value!(temp_v!(4), 1)],
|
||||
reset_block!(),
|
||||
query![put_var!(temp_v!(3), 2)],
|
||||
remove_inference_counter!(perm_v!(3), temp_v!(2)),
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_var!(perm_v!(2), 2)],
|
||||
jmp_call!(2, 5, 0),
|
||||
erase_ball!(),
|
||||
query![put_value!(perm_v!(3), 1),
|
||||
put_unsafe_value!(2, 2),
|
||||
put_value!(perm_v!(1), 3)],
|
||||
deallocate!(),
|
||||
goto_execute!(460, 3), // goto handle_ile/3, 451.
|
||||
try_me_else!(5), // the inner clause.
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
get_ball!(),
|
||||
neck_cut!(),
|
||||
proceed!(),
|
||||
default_trust_me!(),
|
||||
remove_call_policy_check!(),
|
||||
fail!(),
|
||||
try_me_else!(4), // handle_ile/3, 460.
|
||||
fact![get_structure!("inference_limit_exceeded", 1, temp_v!(2), None),
|
||||
unify_value!(temp_v!(1)),
|
||||
get_constant!(atom!("inference_limit_exceeded"), temp_v!(3))],
|
||||
neck_cut!(),
|
||||
proceed!(),
|
||||
default_trust_me!(),
|
||||
remove_call_policy_check!(),
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
goto_execute!(59, 1), // goto throw/1, 59.
|
||||
try_me_else!(6), // end_block/4, 468.
|
||||
query![put_value!(temp_v!(3), 1)],
|
||||
clean_up_block!(),
|
||||
query![put_value!(temp_v!(2), 1)],
|
||||
reset_block!(),
|
||||
proceed!(),
|
||||
default_trust_me!(),
|
||||
query![get_var_in_query!(temp_v!(5), 3),
|
||||
put_value!(temp_v!(4), 2),
|
||||
put_var!(temp_v!(6), 3)],
|
||||
install_inference_counter!(temp_v!(1), temp_v!(4), temp_v!(6)),
|
||||
query![put_value!(temp_v!(5), 1)],
|
||||
reset_block!(),
|
||||
fail!(),
|
||||
compare_execute!(), // compare/3, 480.
|
||||
is_atom!(temp_v!(1)), // atom/1, 481.
|
||||
proceed!(),
|
||||
sort_execute!(), // sort/2, 483.
|
||||
keysort_execute!(), // keysort/2, 484.
|
||||
acyclic_term_execute!(), // acyclic_term/1, 485.
|
||||
cyclic_term_execute!(), // cyclic_term/1, 486.
|
||||
skip_max_list_execute!() // '$skip_max_list', 487.
|
||||
]
|
||||
}
|
||||
|
||||
pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
|
||||
{
|
||||
let mut code_dir = HashMap::new();
|
||||
let mut op_dir = HashMap::new();
|
||||
|
||||
let builtin = ClauseName::BuiltIn("builtin");
|
||||
|
||||
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200, builtin.clone()));
|
||||
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200, builtin.clone()));
|
||||
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200, builtin.clone()));
|
||||
|
||||
// control operators.
|
||||
op_dir.insert((clause_name!("\\+"), Fixity::Pre), (FY, 900, builtin.clone()));
|
||||
op_dir.insert((clause_name!("="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
|
||||
// arithmetic operators.
|
||||
op_dir.insert((clause_name!("is"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("+"), Fixity::In), (YFX, 500, builtin.clone()));
|
||||
op_dir.insert((clause_name!("-"), Fixity::In), (YFX, 500, builtin.clone()));
|
||||
op_dir.insert((clause_name!("/\\"), Fixity::In), (YFX, 500, builtin.clone()));
|
||||
op_dir.insert((clause_name!("\\/"), Fixity::In), (YFX, 500, builtin.clone()));
|
||||
op_dir.insert((clause_name!("xor"), Fixity::In), (YFX, 500, builtin.clone()));
|
||||
op_dir.insert((clause_name!("//"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("div"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("*"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("-"), Fixity::Pre), (FY, 200, builtin.clone()));
|
||||
op_dir.insert((clause_name!("rdiv"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("<<"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!(">>"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("mod"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
op_dir.insert((clause_name!("rem"), Fixity::In), (YFX, 400, builtin.clone()));
|
||||
|
||||
// arithmetic comparison operators.
|
||||
op_dir.insert((clause_name!(">"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("<"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("=\\="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("=:="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!(">="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("=<"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
|
||||
// control operators.
|
||||
op_dir.insert((clause_name!(";"), Fixity::In), (XFY, 1100, builtin.clone()));
|
||||
op_dir.insert((clause_name!("->"), Fixity::In), (XFY, 1050, builtin.clone()));
|
||||
|
||||
op_dir.insert((clause_name!("=.."), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("=="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("\\=="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("@=<"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("@>="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("@<"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("@>"), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700, builtin.clone()));
|
||||
|
||||
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
|
||||
// (an extra register is needed for the predicate name)
|
||||
for arity in 0 .. 63 {
|
||||
code_dir.insert((clause_name!("call"), arity), CodeIndex::from((0, builtin.clone())));
|
||||
}
|
||||
|
||||
code_dir.insert((clause_name!("atomic"), 1), CodeIndex::from((1, builtin.clone())));
|
||||
code_dir.insert((clause_name!("var"), 1), CodeIndex::from((3, builtin.clone())));
|
||||
code_dir.insert((clause_name!("false"), 0), CodeIndex::from((61, builtin.clone())));
|
||||
code_dir.insert((clause_name!("\\+"), 1), CodeIndex::from((62, builtin.clone())));
|
||||
code_dir.insert((clause_name!("duplicate_term"), 2), CodeIndex::from((71, builtin.clone())));
|
||||
code_dir.insert((clause_name!("catch"), 3), CodeIndex::from((5, builtin.clone())));
|
||||
code_dir.insert((clause_name!("throw"), 1), CodeIndex::from((59, builtin.clone())));
|
||||
code_dir.insert((clause_name!("="), 2), CodeIndex::from((73, builtin.clone())));
|
||||
code_dir.insert((clause_name!("true"), 0), CodeIndex::from((75, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!(","), 2), CodeIndex::from((76, builtin.clone())));
|
||||
code_dir.insert((clause_name!(";"), 2), CodeIndex::from((120, builtin.clone())));
|
||||
code_dir.insert((clause_name!("->"), 2), CodeIndex::from((146, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!("functor"), 3), CodeIndex::from((162, builtin.clone())));
|
||||
code_dir.insert((clause_name!("arg"), 3), CodeIndex::from((166, builtin.clone())));
|
||||
code_dir.insert((clause_name!("integer"), 1), CodeIndex::from((163, builtin.clone())));
|
||||
code_dir.insert((clause_name!("display"), 1), CodeIndex::from((208, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!("is"), 2), CodeIndex::from((210, builtin.clone())));
|
||||
code_dir.insert((clause_name!(">"), 2), CodeIndex::from((212, builtin.clone())));
|
||||
code_dir.insert((clause_name!("<"), 2), CodeIndex::from((214, builtin.clone())));
|
||||
code_dir.insert((clause_name!(">="), 2), CodeIndex::from((216, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=<"), 2), CodeIndex::from((218, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=\\="), 2), CodeIndex::from((220, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=:="), 2), CodeIndex::from((222, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=.."), 2), CodeIndex::from((224, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!("length"), 2), CodeIndex::from((277, builtin.clone())));
|
||||
code_dir.insert((clause_name!("setup_call_cleanup"), 3),
|
||||
CodeIndex::from((310, builtin.clone())));
|
||||
code_dir.insert((clause_name!("call_with_inference_limit"), 3),
|
||||
CodeIndex::from((409, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!("compound"), 1), CodeIndex::from((388, builtin.clone())));
|
||||
code_dir.insert((clause_name!("rational"), 1), CodeIndex::from((390, builtin.clone())));
|
||||
code_dir.insert((clause_name!("string"), 1), CodeIndex::from((392, builtin.clone())));
|
||||
code_dir.insert((clause_name!("float"), 1), CodeIndex::from((394, builtin.clone())));
|
||||
code_dir.insert((clause_name!("nonvar"), 1), CodeIndex::from((396, builtin.clone())));
|
||||
|
||||
code_dir.insert((clause_name!("ground"), 1), CodeIndex::from((400, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=="), 2), CodeIndex::from((401, builtin.clone())));
|
||||
code_dir.insert((clause_name!("\\=="), 2), CodeIndex::from((402, builtin.clone())));
|
||||
code_dir.insert((clause_name!("@>="), 2), CodeIndex::from((403, builtin.clone())));
|
||||
code_dir.insert((clause_name!("@=<"), 2), CodeIndex::from((404, builtin.clone())));
|
||||
code_dir.insert((clause_name!("@>"), 2), CodeIndex::from((405, builtin.clone())));
|
||||
code_dir.insert((clause_name!("@<"), 2), CodeIndex::from((406, builtin.clone())));
|
||||
code_dir.insert((clause_name!("=@="), 2), CodeIndex::from((407, builtin.clone())));
|
||||
code_dir.insert((clause_name!("\\=@="), 2), CodeIndex::from((408, builtin.clone())));
|
||||
code_dir.insert((clause_name!("compare"), 3), CodeIndex::from((480, builtin.clone())));
|
||||
code_dir.insert((clause_name!("atom"), 1), CodeIndex::from((481, builtin.clone())));
|
||||
code_dir.insert((clause_name!("sort"), 2), CodeIndex::from((483, builtin.clone())));
|
||||
code_dir.insert((clause_name!("keysort"), 2), CodeIndex::from((484, builtin.clone())));
|
||||
code_dir.insert((clause_name!("acyclic_term"), 1), CodeIndex::from((485, builtin.clone())));
|
||||
code_dir.insert((clause_name!("cyclic_term"), 1), CodeIndex::from((486, builtin.clone())));
|
||||
code_dir.insert((clause_name!("$skip_max_list"), 4), CodeIndex::from((487, builtin.clone())));
|
||||
|
||||
(code_dir, op_dir)
|
||||
}
|
||||
|
||||
pub fn default_build() -> (Code, CodeDir, OpDir)
|
||||
{
|
||||
let builtin_code = get_builtins();
|
||||
let (code_dir, op_dir) = build_code_and_op_dirs();
|
||||
|
||||
(builtin_code, code_dir, op_dir)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn builtin_module() -> Module
|
||||
{
|
||||
let (code_dir, op_dir) = build_code_and_op_dirs();
|
||||
let mut module_decl = module_decl!(clause_name!("builtin"),
|
||||
vec![(clause_name!("atomic"), 1),
|
||||
(clause_name!("var"), 1),
|
||||
(clause_name!("false"), 0),
|
||||
(clause_name!("catch"), 3),
|
||||
(clause_name!("throw"), 1),
|
||||
(clause_name!("(\\+)"), 1),
|
||||
(clause_name!("duplicate_term"), 2),
|
||||
(clause_name!("(=)"), 2),
|
||||
(clause_name!("true"), 0),
|
||||
(clause_name!("(,)"), 2),
|
||||
(clause_name!("(;)"), 2),
|
||||
(clause_name!("->"), 2),
|
||||
(clause_name!("functor"), 3),
|
||||
(clause_name!("arg"), 3),
|
||||
(clause_name!("(=..)"), 3),
|
||||
(clause_name!("display"), 1),
|
||||
(clause_name!("is"), 2),
|
||||
(clause_name!("(>)"), 2),
|
||||
(clause_name!("(<)"), 2),
|
||||
(clause_name!("(>=)"), 2),
|
||||
(clause_name!("(=<)"), 2),
|
||||
(clause_name!("(=\\=)"), 2),
|
||||
(clause_name!("(=:=)"), 2),
|
||||
(clause_name!("(@>)"), 2),
|
||||
(clause_name!("(@<)"), 2),
|
||||
(clause_name!("(@>=)"), 2),
|
||||
(clause_name!("(@=<)"), 2),
|
||||
(clause_name!("(=@=)"), 2),
|
||||
(clause_name!("(\\=@=)"), 2),
|
||||
(clause_name!("(==)"), 2),
|
||||
(clause_name!("(\\==)"), 2),
|
||||
(clause_name!("length"), 2),
|
||||
(clause_name!("compound"), 1),
|
||||
(clause_name!("rational"), 1),
|
||||
(clause_name!("integer"), 1),
|
||||
(clause_name!("string"), 1),
|
||||
(clause_name!("float"), 1),
|
||||
(clause_name!("nonvar"), 1),
|
||||
(clause_name!("ground"), 1),
|
||||
(clause_name!("setup_call_cleanup"), 3),
|
||||
(clause_name!("call_with_inference_limit"), 3),
|
||||
(clause_name!("compare"), 3),
|
||||
(clause_name!("atom"), 1),
|
||||
(clause_name!("sort"), 2),
|
||||
(clause_name!("keysort"), 2),
|
||||
(clause_name!("acyclic_term"), 1),
|
||||
(clause_name!("cyclic_term"), 1),
|
||||
(clause_name!("$skip_max_list"), 4)]);
|
||||
|
||||
for arity in 0 .. 63 {
|
||||
module_decl.exports.push((clause_name!("call"), arity));
|
||||
}
|
||||
|
||||
Module { module_decl, code_dir: as_module_code_dir(code_dir), op_dir }
|
||||
}
|
||||
@@ -19,7 +19,7 @@ pub struct CodeGenerator<TermMarker> {
|
||||
pub struct ConjunctInfo<'a> {
|
||||
pub perm_vs: VariableFixtures<'a>,
|
||||
pub num_of_chunks: usize,
|
||||
pub has_deep_cut: bool
|
||||
pub has_deep_cut: bool,
|
||||
}
|
||||
|
||||
impl<'a> ConjunctInfo<'a>
|
||||
@@ -195,7 +195,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
GenContext::Last(chunk_num)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.update_var_count(chunked_term.post_order_iter());
|
||||
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
|
||||
}
|
||||
@@ -232,14 +232,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
match ctrl.clone() {
|
||||
ControlInstruction::CallClause(ct, arity, pvs, false) =>
|
||||
*ctrl = ControlInstruction::CallClause(ct, arity, pvs, true),
|
||||
ControlInstruction::Goto(p, arity, false) =>
|
||||
*ctrl = ControlInstruction::Goto(p, arity, true),
|
||||
ControlInstruction::JmpBy(arity, offset, pvs, false) =>
|
||||
*ctrl = ControlInstruction::JmpBy(arity, offset, pvs, true),
|
||||
ControlInstruction::IsClause(false, r, at) =>
|
||||
*ctrl = ControlInstruction::IsClause(true, r, at),
|
||||
ControlInstruction::Proceed => {},
|
||||
_ => dealloc_index += 1 // = code.len()
|
||||
_ => dealloc_index += 1
|
||||
},
|
||||
Some(&mut Line::Cut(CutInstruction::Cut(_))) =>
|
||||
dealloc_index += 1,
|
||||
@@ -249,12 +245,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
dealloc_index
|
||||
}
|
||||
|
||||
fn compile_inlined(&mut self, ct: InlinedClauseType, terms: &'a Vec<Box<Term>>,
|
||||
fn compile_inlined(&mut self, ct: &InlinedClauseType, terms: &'a Vec<Box<Term>>,
|
||||
term_loc: GenContext, code: &mut Code)
|
||||
-> Result<(), ParserError>
|
||||
{
|
||||
match ct {
|
||||
InlinedClauseType::CompareNumber(cmp) => {
|
||||
&InlinedClauseType::CompareNumber(cmp, ..) => {
|
||||
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
|
||||
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
|
||||
|
||||
@@ -265,7 +261,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
at_1.unwrap_or(interm!(1)),
|
||||
at_2.unwrap_or(interm!(2))));
|
||||
},
|
||||
InlinedClauseType::IsAtom =>
|
||||
&InlinedClauseType::IsAtom(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Atom(_)) => {
|
||||
code.push(succeed!());
|
||||
@@ -278,7 +274,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsAtomic =>
|
||||
&InlinedClauseType::IsAtomic(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
|
||||
code.push(fail!());
|
||||
@@ -291,7 +287,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(is_atomic!(r));
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsCompound =>
|
||||
&InlinedClauseType::IsCompound(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Clause(..) | &Term::Cons(..) => {
|
||||
code.push(succeed!());
|
||||
@@ -304,7 +300,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsRational =>
|
||||
&InlinedClauseType::IsRational(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Number(Number::Rational(_))) => {
|
||||
code.push(succeed!());
|
||||
@@ -317,7 +313,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsFloat =>
|
||||
&InlinedClauseType::IsFloat(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Number(Number::Float(_))) => {
|
||||
code.push(succeed!());
|
||||
@@ -330,7 +326,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsString =>
|
||||
&InlinedClauseType::IsString(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::String(_)) => {
|
||||
code.push(succeed!());
|
||||
@@ -343,7 +339,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsNonVar =>
|
||||
&InlinedClauseType::IsNonVar(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::AnonVar => {
|
||||
code.push(fail!());
|
||||
@@ -356,7 +352,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(succeed!());
|
||||
}
|
||||
},
|
||||
InlinedClauseType::IsInteger =>
|
||||
&InlinedClauseType::IsInteger(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(_, Constant::Number(Number::Integer(_))) => {
|
||||
code.push(succeed!());
|
||||
@@ -369,7 +365,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
code.push(fail!());
|
||||
},
|
||||
},
|
||||
InlinedClauseType::IsVar =>
|
||||
&InlinedClauseType::IsVar(..) =>
|
||||
match terms[0].as_ref() {
|
||||
&Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => {
|
||||
code.push(fail!());
|
||||
@@ -408,6 +404,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
};
|
||||
|
||||
match *term {
|
||||
&QueryTerm::GetLevelAndUnify(ref cell, ref var) => {
|
||||
let mut target = Vec::new();
|
||||
|
||||
self.marker.reset_arg(1);
|
||||
self.marker.mark_var(var.clone(), Level::Shallow, cell,
|
||||
term_loc, &mut target);
|
||||
|
||||
if !target.is_empty() {
|
||||
code.push(Line::Query(target));
|
||||
}
|
||||
|
||||
code.push(get_level_and_unify!(cell.get().norm()));
|
||||
},
|
||||
&QueryTerm::UnblockedCut(ref cell) =>
|
||||
code.push(set_cp!(cell.get().norm())),
|
||||
&QueryTerm::BlockedCut =>
|
||||
@@ -416,7 +425,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
} else {
|
||||
Line::Cut(CutInstruction::Cut(perm_v!(1)))
|
||||
}),
|
||||
&QueryTerm::Clause(_, ClauseType::Is, ref terms) => {
|
||||
&QueryTerm::Clause(_, ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ref terms)
|
||||
=>
|
||||
{
|
||||
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
|
||||
code.append(&mut acode);
|
||||
|
||||
@@ -445,7 +456,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
|
||||
}
|
||||
}
|
||||
},
|
||||
&QueryTerm::Clause(_, ClauseType::Inlined(ct), ref terms) =>
|
||||
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms) =>
|
||||
try!(self.compile_inlined(ct, terms, term_loc, code)),
|
||||
_ => {
|
||||
let num_perm_vars = if chunk_num == 0 {
|
||||
|
||||
317
src/prolog/compile.rs
Normal file
317
src/prolog/compile.rs
Normal file
@@ -0,0 +1,317 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::toplevel::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn print_code(code: &Code) {
|
||||
for clause in code {
|
||||
match clause {
|
||||
&Line::Arithmetic(ref arith) =>
|
||||
println!("{}", arith),
|
||||
&Line::Fact(ref fact) =>
|
||||
for fact_instr in fact {
|
||||
println!("{}", fact_instr);
|
||||
},
|
||||
&Line::Cut(ref cut) =>
|
||||
println!("{}", cut),
|
||||
&Line::Choice(ref choice) =>
|
||||
println!("{}", choice),
|
||||
&Line::Control(ref control) =>
|
||||
println!("{}", control),
|
||||
&Line::IndexedChoice(ref choice) =>
|
||||
println!("{}", choice),
|
||||
&Line::Indexing(ref indexing) =>
|
||||
println!("{}", indexing),
|
||||
&Line::Query(ref query) =>
|
||||
for query_instr in query {
|
||||
println!("{}", query_instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait TLInfo {
|
||||
fn update_entry_index(&self, &ClauseName, usize, CodeIndex, &mut CodeIndex, usize);
|
||||
|
||||
// give the correct CodePtr offsets to CallClause's whose types are
|
||||
// Named and Op. Enable late binding by setting to the default.
|
||||
fn label_clauses(&self, code_size: usize, code_dir: &mut CodeDir, code: &mut Code)
|
||||
{
|
||||
for line in code.iter_mut() {
|
||||
if let &mut Line::Control(ControlInstruction::CallClause(ref mut ct, a1, ..)) = line {
|
||||
match ct {
|
||||
&mut ClauseType::Named(ref n1, ref mut cp)
|
||||
| &mut ClauseType::Op(ref n1, _, ref mut cp) => {
|
||||
let entry = code_dir.entry((n1.clone(), a1)).or_insert(CodeIndex::default());
|
||||
self.update_entry_index(n1, a1, entry.clone(), cp, code_size);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DeclInfo { name: ClauseName, arity: usize, module_name: ClauseName }
|
||||
|
||||
impl TLInfo for DeclInfo {
|
||||
fn update_entry_index(&self, n1: &ClauseName, a1: usize, entry: CodeIndex,
|
||||
cp: &mut CodeIndex, code_size: usize)
|
||||
{
|
||||
let (name, arity) = (self.name.clone(), self.arity);
|
||||
|
||||
{
|
||||
let mut entry = entry.0.borrow_mut();
|
||||
|
||||
if entry.0 == IndexPtr::Undefined {
|
||||
if &name == n1 && arity == a1 {
|
||||
entry.0 = IndexPtr::Index(code_size);
|
||||
}
|
||||
}
|
||||
|
||||
entry.1 = self.module_name.clone();
|
||||
}
|
||||
|
||||
*cp = entry;
|
||||
}
|
||||
}
|
||||
|
||||
struct QueryInfo {}
|
||||
|
||||
impl TLInfo for QueryInfo {
|
||||
fn update_entry_index(&self, _: &ClauseName, _: usize, entry: CodeIndex,
|
||||
cp: &mut CodeIndex, _: usize)
|
||||
{
|
||||
*cp = entry;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_code(wam: &Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
|
||||
{
|
||||
let mut worker = TopLevelWorker::new(buffer.as_bytes(), wam.atom_tbl());
|
||||
worker.parse_code(&wam.op_dir)
|
||||
}
|
||||
|
||||
// throw errors if declaration or query found.
|
||||
fn compile_relation(tl: &TopLevel) -> Result<Code, ParserError>
|
||||
{
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
|
||||
match tl {
|
||||
&TopLevel::Declaration(_) | &TopLevel::Query(_) =>
|
||||
Err(ParserError::ExpectedRel),
|
||||
&TopLevel::Predicate(ref clauses) =>
|
||||
cg.compile_predicate(&clauses.0),
|
||||
&TopLevel::Fact(ref fact) =>
|
||||
Ok(cg.compile_fact(fact)),
|
||||
&TopLevel::Rule(ref rule) =>
|
||||
cg.compile_rule(rule)
|
||||
}
|
||||
}
|
||||
|
||||
// set first jmp_by_call or jmp_by_index instruction to code.len() -
|
||||
// idx, where idx is the place it occurs. It only does this to the
|
||||
// *first* uninitialized jmp index it encounters, then returns.
|
||||
fn set_first_index(code: &mut Code)
|
||||
{
|
||||
let code_len = code.len();
|
||||
|
||||
for (idx, line) in code.iter_mut().enumerate() {
|
||||
match line {
|
||||
&mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) if *offset == 0 => {
|
||||
*offset = code_len - idx;
|
||||
break;
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_appendix(code: &mut Code, queue: Vec<TopLevel>) -> Result<(), ParserError>
|
||||
{
|
||||
for tl in queue.iter() {
|
||||
set_first_index(code);
|
||||
code.append(&mut compile_relation(tl)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>, code_size: usize,
|
||||
code_dir: &mut CodeDir)
|
||||
-> Result<(Code, AllocVarDict), ParserError>
|
||||
{
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
let mut code = try!(cg.compile_query(&terms));
|
||||
|
||||
compile_appendix(&mut code, queue)?;
|
||||
|
||||
let query_info = QueryInfo {};
|
||||
query_info.label_clauses(code_size, code_dir, &mut code);
|
||||
|
||||
Ok((code, cg.take_vars()))
|
||||
}
|
||||
|
||||
fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
|
||||
{
|
||||
match tl {
|
||||
TopLevel::Declaration(Declaration::Op(op_decl)) => {
|
||||
try_eval_session!(op_decl.submit(clause_name!("user"), &mut wam.op_dir));
|
||||
EvalSession::EntrySuccess
|
||||
},
|
||||
TopLevel::Declaration(Declaration::UseModule(name)) =>
|
||||
wam.use_module_in_toplevel(name),
|
||||
TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) =>
|
||||
wam.use_qualified_module_in_toplevel(name, exports),
|
||||
TopLevel::Declaration(_) =>
|
||||
EvalSession::from(ParserError::InvalidModuleDecl),
|
||||
_ => {
|
||||
let name = try_eval_session!(if let Some(name) = tl.name() {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err(SessionError::NamelessEntry)
|
||||
});
|
||||
|
||||
let mut code = try_eval_session!(compile_relation(&tl));
|
||||
try_eval_session!(compile_appendix(&mut code, queue));
|
||||
|
||||
let decl_info = DeclInfo { name: name.clone(), arity: tl.arity(),
|
||||
module_name: clause_name!("user") };
|
||||
|
||||
decl_info.label_clauses(wam.code_size(), &mut wam.code_dir, &mut code);
|
||||
|
||||
if !code.is_empty() {
|
||||
wam.add_user_code(name, tl.arity(), code, tl.as_predicate().ok().unwrap())
|
||||
} else {
|
||||
EvalSession::from(SessionError::ImpermissibleEntry(String::from("no code generated.")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession
|
||||
{
|
||||
match tl {
|
||||
TopLevelPacket::Query(terms, queue) =>
|
||||
match compile_query(terms, queue, wam.code_size(), &mut wam.code_dir) {
|
||||
Ok((mut code, vars)) => wam.submit_query(code, vars),
|
||||
Err(e) => EvalSession::from(e)
|
||||
},
|
||||
TopLevelPacket::Decl(tl, queue) =>
|
||||
compile_decl(wam, tl, queue)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
|
||||
{
|
||||
fn get_module_name(module: &Option<Module>) -> ClauseName {
|
||||
match module {
|
||||
&Some(ref module) => module.module_decl.name.clone(),
|
||||
_ => ClauseName::BuiltIn("user")
|
||||
}
|
||||
}
|
||||
|
||||
let mut module: Option<Module> = None;
|
||||
|
||||
let mut code_dir = CodeDir::new();
|
||||
let mut op_dir = default_op_dir();
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
let mut worker = TopLevelWorker::new(src_str.as_bytes(), wam.atom_tbl());
|
||||
|
||||
let tls = {
|
||||
let indices = MachineCodeIndex { code_dir: &mut code_dir,
|
||||
op_dir: &mut op_dir };
|
||||
|
||||
try_eval_session!(worker.parse_batch(&wam, indices))
|
||||
};
|
||||
|
||||
for tl in tls {
|
||||
match tl {
|
||||
TopLevelPacket::Query(..) =>
|
||||
return EvalSession::from(ParserError::ExpectedRel),
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Module(module_decl)), _) =>
|
||||
if module.is_none() {
|
||||
module = Some(Module::new(module_decl));
|
||||
} else {
|
||||
return EvalSession::from(ParserError::InvalidModuleDecl);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseModule(name)), _) => {
|
||||
if let Some(ref submodule) = wam.get_module(name.clone()) {
|
||||
if let Some(ref mut module) = module {
|
||||
let mut code_index = machine_code_index!(&mut code_dir, &mut op_dir);
|
||||
|
||||
module.use_module(submodule);
|
||||
code_index.use_module(submodule);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
return EvalSession::from(SessionError::ModuleNotFound);
|
||||
}
|
||||
|
||||
wam.use_module_in_toplevel(name);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)), _)
|
||||
=>
|
||||
{
|
||||
if let Some(ref submodule) = wam.get_module(name.clone()) {
|
||||
if let Some(ref mut module) = module {
|
||||
let mut code_index = machine_code_index!(&mut code_dir, &mut op_dir);
|
||||
|
||||
module.use_qualified_module(submodule, &exports);
|
||||
code_index.use_qualified_module(submodule, &exports);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
return EvalSession::from(SessionError::ModuleNotFound);
|
||||
}
|
||||
|
||||
wam.use_qualified_module_in_toplevel(name, exports);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {},
|
||||
TopLevelPacket::Decl(decl, queue) => {
|
||||
let p = code.len() + wam.code_size();
|
||||
let mut decl_code = try_eval_session!(compile_relation(&decl));
|
||||
|
||||
try_eval_session!(compile_appendix(&mut decl_code, queue));
|
||||
|
||||
let name = try_eval_session!(if let Some(name) = decl.name() {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err(SessionError::NamelessEntry)
|
||||
});
|
||||
|
||||
let module_name = get_module_name(&module);
|
||||
let decl_info = DeclInfo { name, arity: decl.arity(),
|
||||
module_name: module_name.clone() };
|
||||
|
||||
{
|
||||
let idx = code_dir.entry((decl_info.name.clone(), decl_info.arity))
|
||||
.or_insert(CodeIndex::default());
|
||||
|
||||
set_code_index!(idx, IndexPtr::Index(p), module_name);
|
||||
}
|
||||
|
||||
decl_info.label_clauses(p, &mut code_dir, &mut decl_code);
|
||||
code.extend(decl_code.into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut module) = module {
|
||||
module.code_dir.extend(as_module_code_dir(code_dir));
|
||||
module.op_dir.extend(op_dir.into_iter());
|
||||
|
||||
wam.add_module(module, code);
|
||||
} else {
|
||||
wam.add_batched_code(code, code_dir);
|
||||
wam.add_batched_ops(op_dir);
|
||||
}
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
@@ -16,7 +16,7 @@ pub enum TokenOrRedirect {
|
||||
OpenList(Rc<Cell<bool>>),
|
||||
CloseList(Rc<Cell<bool>>),
|
||||
HeadTailSeparator,
|
||||
Space
|
||||
// Space
|
||||
}
|
||||
|
||||
pub trait HCValueFormatter {
|
||||
@@ -119,19 +119,15 @@ impl HCValueFormatter for TermFormatter {
|
||||
match fixity {
|
||||
Fixity::Post => {
|
||||
state_stack.push(TokenOrRedirect::Atom(ct.name()));
|
||||
state_stack.push(TokenOrRedirect::Space);
|
||||
state_stack.push(TokenOrRedirect::Redirect);
|
||||
},
|
||||
Fixity::Pre => {
|
||||
state_stack.push(TokenOrRedirect::Redirect);
|
||||
state_stack.push(TokenOrRedirect::Space);
|
||||
state_stack.push(TokenOrRedirect::Atom(ct.name()));
|
||||
},
|
||||
Fixity::In => {
|
||||
state_stack.push(TokenOrRedirect::Redirect);
|
||||
state_stack.push(TokenOrRedirect::Space);
|
||||
state_stack.push(TokenOrRedirect::Atom(ct.name()));
|
||||
state_stack.push(TokenOrRedirect::Space);
|
||||
state_stack.push(TokenOrRedirect::Redirect);
|
||||
}
|
||||
}
|
||||
@@ -285,8 +281,8 @@ impl<'a, Formatter: HCValueFormatter, Outputter: HCValueOutputter>
|
||||
loop {
|
||||
if let Some(loc_data) = self.state_stack.pop() {
|
||||
match loc_data {
|
||||
TokenOrRedirect::Space =>
|
||||
self.outputter.append(" "),
|
||||
// TokenOrRedirect::Space =>
|
||||
// self.outputter.append(" "),
|
||||
TokenOrRedirect::Atom(atom) =>
|
||||
self.outputter.append(atom.as_str()),
|
||||
TokenOrRedirect::Redirect =>
|
||||
|
||||
@@ -2,6 +2,7 @@ use prolog::ast::*;
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum IntIndex {
|
||||
@@ -132,7 +133,7 @@ impl CodeOffsets {
|
||||
|
||||
if con_ind.len() > 1 {
|
||||
let index = Self::flatten_index(con_ind, prelude.len());
|
||||
let instr = IndexingInstruction::SwitchOnConstant(index.len(), index);
|
||||
let instr = IndexingInstruction::SwitchOnConstant(index.len(), Rc::new(index));
|
||||
|
||||
prelude.push_front(Line::from(instr));
|
||||
|
||||
@@ -152,7 +153,7 @@ impl CodeOffsets {
|
||||
|
||||
if str_ind.len() > 1 {
|
||||
let index = Self::flatten_index(str_ind, prelude.len());
|
||||
let instr = IndexingInstruction::SwitchOnStructure(index.len(), index);
|
||||
let instr = IndexingInstruction::SwitchOnStructure(index.len(), Rc::new(index));
|
||||
|
||||
prelude.push_front(Line::from(instr));
|
||||
|
||||
|
||||
392
src/prolog/io.rs
392
src/prolog/io.rs
@@ -1,10 +1,6 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::toplevel::*;
|
||||
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::input::TermRead;
|
||||
@@ -133,20 +129,8 @@ impl fmt::Display for ControlInstruction {
|
||||
write!(f, "execute {}/{}, {}", ct, arity, pvs),
|
||||
&ControlInstruction::CallClause(ref ct, arity, pvs, false) =>
|
||||
write!(f, "call {}/{}, {}", ct, arity, pvs),
|
||||
&ControlInstruction::CheckCpExecute =>
|
||||
write!(f, "check_cp_execute"),
|
||||
&ControlInstruction::Deallocate =>
|
||||
write!(f, "deallocate"),
|
||||
&ControlInstruction::GetCleanerCall =>
|
||||
write!(f, "get_cleaner_call"),
|
||||
&ControlInstruction::Goto(p, arity, false) =>
|
||||
write!(f, "goto_call {}/{}", p, arity),
|
||||
&ControlInstruction::Goto(p, arity, true) =>
|
||||
write!(f, "goto_execute {}/{}", p, arity),
|
||||
&ControlInstruction::IsClause(false, r, ref at) =>
|
||||
write!(f, "is_call {}, {}", r, at),
|
||||
&ControlInstruction::IsClause(true, r, ref at) =>
|
||||
write!(f, "is_execute {}, {}", r, at),
|
||||
&ControlInstruction::JmpBy(arity, offset, pvs, false) =>
|
||||
write!(f, "jmp_by_call {}/{}, {}", offset, arity, pvs),
|
||||
&ControlInstruction::JmpBy(arity, offset, pvs, true) =>
|
||||
@@ -170,69 +154,6 @@ impl fmt::Display for IndexedChoiceInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BuiltInInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&BuiltInInstruction::CallInlined(InlinedClauseType::CompareNumber(cmp), ref rs) =>
|
||||
write!(f, "number_test {}, {}, {}", cmp, &rs[0], &rs[1]),
|
||||
&BuiltInInstruction::CallInlined(ict, ref rs) =>
|
||||
write!(f, "call_inlined_{}, {}", ict.name(), &rs[0]),
|
||||
&BuiltInInstruction::CleanUpBlock =>
|
||||
write!(f, "clean_up_block"),
|
||||
&BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) =>
|
||||
write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2),
|
||||
&BuiltInInstruction::DefaultRetryMeElse(o) =>
|
||||
write!(f, "default_retry_me_else {}", o),
|
||||
&BuiltInInstruction::DefaultSetCutPoint(r) =>
|
||||
write!(f, "default_set_cp {}", r),
|
||||
&BuiltInInstruction::DefaultTrustMe =>
|
||||
write!(f, "default_trust_me"),
|
||||
&BuiltInInstruction::InstallInferenceCounter(r1, r2, r3) =>
|
||||
write!(f, "install_inference_counter {}, {}, {}", r1, r2, r3),
|
||||
&BuiltInInstruction::EraseBall =>
|
||||
write!(f, "erase_ball"),
|
||||
&BuiltInInstruction::Fail =>
|
||||
write!(f, "false"),
|
||||
&BuiltInInstruction::GetArg(false) =>
|
||||
write!(f, "get_arg_call X1, X2, X3"),
|
||||
&BuiltInInstruction::GetArg(true) =>
|
||||
write!(f, "get_arg_execute X1, X2, X3"),
|
||||
&BuiltInInstruction::GetBall =>
|
||||
write!(f, "get_ball X1"),
|
||||
&BuiltInInstruction::GetCurrentBlock =>
|
||||
write!(f, "get_current_block X1"),
|
||||
&BuiltInInstruction::GetCutPoint(r) =>
|
||||
write!(f, "get_cp {}", r),
|
||||
&BuiltInInstruction::InferenceLevel(r1, r2) =>
|
||||
write!(f, "inference_level {}, {}", r1, r2),
|
||||
&BuiltInInstruction::InstallCleaner =>
|
||||
write!(f, "install_cleaner"),
|
||||
&BuiltInInstruction::InstallNewBlock =>
|
||||
write!(f, "install_new_block"),
|
||||
&BuiltInInstruction::InternalCallN =>
|
||||
write!(f, "internal_call_N"),
|
||||
&BuiltInInstruction::RemoveCallPolicyCheck =>
|
||||
write!(f, "remove_call_policy_check"),
|
||||
&BuiltInInstruction::RemoveInferenceCounter(r1, r2) =>
|
||||
write!(f, "remove_inference_counter {}, {}", r1, r2),
|
||||
&BuiltInInstruction::ResetBlock =>
|
||||
write!(f, "reset_block"),
|
||||
&BuiltInInstruction::RestoreCutPolicy =>
|
||||
write!(f, "restore_cut_point"),
|
||||
&BuiltInInstruction::SetBall =>
|
||||
write!(f, "set_ball"),
|
||||
&BuiltInInstruction::SetCutPoint(r) =>
|
||||
write!(f, "set_cp {}", r),
|
||||
&BuiltInInstruction::Succeed =>
|
||||
write!(f, "true"),
|
||||
&BuiltInInstruction::UnwindStack =>
|
||||
write!(f, "unwind_stack"),
|
||||
&BuiltInInstruction::Unify =>
|
||||
write!(f, "unify"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ChoiceInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -330,7 +251,9 @@ impl fmt::Display for CutInstruction {
|
||||
&CutInstruction::NeckCut =>
|
||||
write!(f, "neck_cut"),
|
||||
&CutInstruction::GetLevel(r) =>
|
||||
write!(f, "get_level {}", r)
|
||||
write!(f, "get_level {}", r),
|
||||
&CutInstruction::GetLevelAndUnify(r) =>
|
||||
write!(f, "get_level_and_unify {}", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,42 +289,6 @@ impl fmt::Display for RegType {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_code(code: &Code) {
|
||||
for clause in code {
|
||||
match clause {
|
||||
&Line::Arithmetic(ref arith) =>
|
||||
println!("{}", arith),
|
||||
&Line::Fact(ref fact) =>
|
||||
for fact_instr in fact {
|
||||
println!("{}", fact_instr);
|
||||
},
|
||||
&Line::BuiltIn(ref instr) =>
|
||||
println!("{}", instr),
|
||||
&Line::Cut(ref cut) =>
|
||||
println!("{}", cut),
|
||||
&Line::Choice(ref choice) =>
|
||||
println!("{}", choice),
|
||||
&Line::Control(ref control) =>
|
||||
println!("{}", control),
|
||||
&Line::IndexedChoice(ref choice) =>
|
||||
println!("{}", choice),
|
||||
&Line::Indexing(ref indexing) =>
|
||||
println!("{}", indexing),
|
||||
&Line::Query(ref query) =>
|
||||
for query_instr in query {
|
||||
println!("{}", query_instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_code(wam: &Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
|
||||
{
|
||||
let mut worker = TopLevelWorker::new(buffer.as_bytes(), wam.atom_tbl());
|
||||
worker.parse_code(&wam.op_dir)
|
||||
}
|
||||
|
||||
pub enum Input {
|
||||
Quit,
|
||||
Clear,
|
||||
@@ -441,279 +328,6 @@ pub fn read() -> Input {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait TLInfo {
|
||||
fn update_entry_index(&self, &ClauseName, usize, CodeIndex, &mut CodeIndex, usize);
|
||||
|
||||
// give the correct CodePtr offsets to CallClause's whose types are
|
||||
// Named and Op. Enable late binding by setting to the default.
|
||||
fn label_clauses(&self, code_size: usize, code_dir: &mut CodeDir, code: &mut Code)
|
||||
{
|
||||
for line in code.iter_mut() {
|
||||
if let &mut Line::Control(ControlInstruction::CallClause(ref mut ct, a1, ..)) = line {
|
||||
match ct {
|
||||
&mut ClauseType::Named(ref n1, ref mut cp)
|
||||
| &mut ClauseType::Op(ref n1, _, ref mut cp) => {
|
||||
let entry = code_dir.entry((n1.clone(), a1)).or_insert(CodeIndex::default());
|
||||
self.update_entry_index(n1, a1, entry.clone(), cp, code_size);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DeclInfo { name: ClauseName, arity: usize, module_name: ClauseName }
|
||||
|
||||
impl TLInfo for DeclInfo {
|
||||
fn update_entry_index(&self, n1: &ClauseName, a1: usize, entry: CodeIndex,
|
||||
cp: &mut CodeIndex, code_size: usize)
|
||||
{
|
||||
let (name, arity) = (self.name.clone(), self.arity);
|
||||
|
||||
{
|
||||
let mut entry = entry.0.borrow_mut();
|
||||
|
||||
if entry.0 == IndexPtr::Undefined {
|
||||
if &name == n1 && arity == a1 {
|
||||
entry.0 = IndexPtr::Index(code_size);
|
||||
}
|
||||
}
|
||||
|
||||
entry.1 = self.module_name.clone();
|
||||
}
|
||||
|
||||
*cp = entry;
|
||||
}
|
||||
}
|
||||
|
||||
struct QueryInfo {}
|
||||
|
||||
impl TLInfo for QueryInfo {
|
||||
fn update_entry_index(&self, _: &ClauseName, _: usize, entry: CodeIndex,
|
||||
cp: &mut CodeIndex, _: usize)
|
||||
{
|
||||
*cp = entry;
|
||||
}
|
||||
}
|
||||
|
||||
// throw errors if declaration or query found.
|
||||
fn compile_relation(tl: &TopLevel) -> Result<Code, ParserError>
|
||||
{
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
|
||||
match tl {
|
||||
&TopLevel::Declaration(_) | &TopLevel::Query(_) =>
|
||||
Err(ParserError::ExpectedRel),
|
||||
&TopLevel::Predicate(ref clauses) =>
|
||||
cg.compile_predicate(&clauses.0),
|
||||
&TopLevel::Fact(ref fact) =>
|
||||
Ok(cg.compile_fact(fact)),
|
||||
&TopLevel::Rule(ref rule) =>
|
||||
cg.compile_rule(rule)
|
||||
}
|
||||
}
|
||||
|
||||
// set first jmp_by_call or jmp_by_index instruction to code.len() -
|
||||
// idx, where idx is the place it occurs. It only does this to the
|
||||
// *first* uninitialized jmp index it encounters, then returns.
|
||||
fn set_first_index(code: &mut Code)
|
||||
{
|
||||
let code_len = code.len();
|
||||
|
||||
for (idx, line) in code.iter_mut().enumerate() {
|
||||
match line {
|
||||
&mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) if *offset == 0 => {
|
||||
*offset = code_len - idx;
|
||||
break;
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_appendix(code: &mut Code, queue: Vec<TopLevel>) -> Result<(), ParserError>
|
||||
{
|
||||
for tl in queue.iter() {
|
||||
set_first_index(code);
|
||||
code.append(&mut compile_relation(tl)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>, code_size: usize,
|
||||
code_dir: &mut CodeDir)
|
||||
-> Result<(Code, AllocVarDict), ParserError>
|
||||
{
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||
let mut code = try!(cg.compile_query(&terms));
|
||||
|
||||
compile_appendix(&mut code, queue)?;
|
||||
|
||||
let query_info = QueryInfo {};
|
||||
query_info.label_clauses(code_size, code_dir, &mut code);
|
||||
|
||||
Ok((code, cg.take_vars()))
|
||||
}
|
||||
|
||||
fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
|
||||
{
|
||||
match tl {
|
||||
TopLevel::Declaration(Declaration::Op(op_decl)) => {
|
||||
try_eval_session!(op_decl.submit(clause_name!("user"), &mut wam.op_dir));
|
||||
EvalSession::EntrySuccess
|
||||
},
|
||||
TopLevel::Declaration(Declaration::UseModule(name)) =>
|
||||
wam.use_module_in_toplevel(name),
|
||||
TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) =>
|
||||
wam.use_qualified_module_in_toplevel(name, exports),
|
||||
TopLevel::Declaration(_) =>
|
||||
EvalSession::from(ParserError::InvalidModuleDecl),
|
||||
_ => {
|
||||
let name = try_eval_session!(if let Some(name) = tl.name() {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err(SessionError::NamelessEntry)
|
||||
});
|
||||
|
||||
let mut code = try_eval_session!(compile_relation(&tl));
|
||||
try_eval_session!(compile_appendix(&mut code, queue));
|
||||
|
||||
let decl_info = DeclInfo { name: name.clone(), arity: tl.arity(),
|
||||
module_name: clause_name!("user") };
|
||||
|
||||
decl_info.label_clauses(wam.code_size(), &mut wam.code_dir, &mut code);
|
||||
|
||||
if !code.is_empty() {
|
||||
wam.add_user_code(name, tl.arity(), code, tl.as_predicate().ok().unwrap())
|
||||
} else {
|
||||
EvalSession::from(SessionError::ImpermissibleEntry(String::from("no code generated.")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession
|
||||
{
|
||||
match tl {
|
||||
TopLevelPacket::Query(terms, queue) =>
|
||||
match compile_query(terms, queue, wam.code_size(), &mut wam.code_dir) {
|
||||
Ok((mut code, vars)) => wam.submit_query(code, vars),
|
||||
Err(e) => EvalSession::from(e)
|
||||
},
|
||||
TopLevelPacket::Decl(tl, queue) =>
|
||||
compile_decl(wam, tl, queue)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
|
||||
{
|
||||
fn get_module_name(module: &Option<Module>) -> ClauseName {
|
||||
match module {
|
||||
&Some(ref module) => module.module_decl.name.clone(),
|
||||
_ => ClauseName::BuiltIn("user")
|
||||
}
|
||||
}
|
||||
|
||||
let mut module: Option<Module> = None;
|
||||
let (mut code_dir, mut op_dir) = build_code_and_op_dirs();
|
||||
|
||||
let mut code = Vec::new();
|
||||
|
||||
let mut worker = TopLevelWorker::new(src_str.as_bytes(), wam.atom_tbl());
|
||||
let tls = try_eval_session!(worker.parse_batch(&mut op_dir));
|
||||
|
||||
for tl in tls {
|
||||
match tl {
|
||||
TopLevelPacket::Query(..) =>
|
||||
return EvalSession::from(ParserError::ExpectedRel),
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Module(module_decl)), _) =>
|
||||
if module.is_none() {
|
||||
let (builtin_code_dir, builtin_op_dir) = build_code_and_op_dirs();
|
||||
|
||||
code_dir.extend(builtin_code_dir.into_iter());
|
||||
op_dir.extend(builtin_op_dir.into_iter());
|
||||
|
||||
module = Some(Module::new(module_decl));
|
||||
} else {
|
||||
return EvalSession::from(ParserError::InvalidModuleDecl);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseModule(name)), _) => {
|
||||
if let Some(ref submodule) = wam.get_module(name.clone()) {
|
||||
if let Some(ref mut module) = module {
|
||||
let mut code_index = machine_code_index!(&mut code_dir, &mut op_dir);
|
||||
|
||||
module.use_module(submodule);
|
||||
code_index.use_module(submodule);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
return EvalSession::from(SessionError::ModuleNotFound);
|
||||
}
|
||||
|
||||
wam.use_module_in_toplevel(name);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)), _) => {
|
||||
if let Some(ref submodule) = wam.get_module(name.clone()) {
|
||||
if let Some(ref mut module) = module {
|
||||
let mut code_index = machine_code_index!(&mut code_dir, &mut op_dir);
|
||||
|
||||
module.use_qualified_module(submodule, &exports);
|
||||
code_index.use_qualified_module(submodule, &exports);
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
return EvalSession::from(SessionError::ModuleNotFound);
|
||||
}
|
||||
|
||||
wam.use_qualified_module_in_toplevel(name, exports);
|
||||
},
|
||||
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {},
|
||||
TopLevelPacket::Decl(decl, queue) => {
|
||||
let p = code.len() + wam.code_size();
|
||||
let mut decl_code = try_eval_session!(compile_relation(&decl));
|
||||
|
||||
try_eval_session!(compile_appendix(&mut decl_code, queue));
|
||||
|
||||
let name = try_eval_session!(if let Some(name) = decl.name() {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err(SessionError::NamelessEntry)
|
||||
});
|
||||
|
||||
let module_name = get_module_name(&module);
|
||||
let decl_info = DeclInfo { name, arity: decl.arity(),
|
||||
module_name: module_name.clone() };
|
||||
|
||||
{
|
||||
let idx = code_dir.entry((decl_info.name.clone(), decl_info.arity))
|
||||
.or_insert(CodeIndex::default());
|
||||
|
||||
set_code_index!(idx, IndexPtr::Index(p), module_name);
|
||||
}
|
||||
|
||||
decl_info.label_clauses(p, &mut code_dir, &mut decl_code);
|
||||
code.extend(decl_code.into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mut module) = module {
|
||||
module.code_dir.extend(as_module_code_dir(code_dir));
|
||||
module.op_dir.extend(op_dir.into_iter());
|
||||
|
||||
wam.add_module(module, code);
|
||||
} else {
|
||||
wam.add_batched_code(code, code_dir);
|
||||
wam.add_batched_ops(op_dir);
|
||||
}
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
|
||||
fn error_string(e: &String) -> String {
|
||||
format!("error: exception thrown: {}", e)
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ impl<'a> QueryIterator<'a> {
|
||||
let state = TermIterState::Var(Level::Root, cell, rc_atom!("!"));
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
&QueryTerm::GetLevelAndUnify(ref cell, ref var) => {
|
||||
let state = TermIterState::Var(Level::Root, cell, var.clone());
|
||||
QueryIterator { state_stack: vec![state] }
|
||||
},
|
||||
&QueryTerm::Jump(ref vars) => {
|
||||
let state_stack = vars.iter().rev().map(|t| {
|
||||
TermIterState::subterm_to_state(Level::Shallow, t)
|
||||
@@ -337,11 +341,17 @@ impl<'a> ChunkedIterator<'a>
|
||||
self.deep_cut_encountered = true;
|
||||
}
|
||||
},
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::GetLevelAndUnify(..)) => {
|
||||
result.push(term);
|
||||
arity = 1;
|
||||
break;
|
||||
},
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) =>
|
||||
result.push(term),
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), _)) =>
|
||||
result.push(term),
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::CallN, ref subterms)) => {
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::CallN, ref subterms)) =>
|
||||
{
|
||||
result.push(term);
|
||||
arity = subterms.len() + 1;
|
||||
break;
|
||||
|
||||
193
src/prolog/lib/builtins.pl
Normal file
193
src/prolog/lib/builtins.pl
Normal file
@@ -0,0 +1,193 @@
|
||||
:- op(400, yfx, /).
|
||||
|
||||
:- module(builtins, [(=)/2, (+)/2, (*)/2, (-)/2, (/)/2, (/\)/2,
|
||||
(\/)/2, (is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2,
|
||||
(>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2,
|
||||
(-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2, (=..)/2, (==)/2,
|
||||
(\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2,
|
||||
catch/3, throw/1, true/0, false/0]).
|
||||
|
||||
% arithmetic operators.
|
||||
:- op(700, xfx, is).
|
||||
:- op(500, yfx, +).
|
||||
:- op(500, yfx, -).
|
||||
:- op(400, yfx, *).
|
||||
:- op(500, yfx, /\).
|
||||
:- op(500, yfx, \/).
|
||||
:- op(500, yfx, xor).
|
||||
:- op(400, yfx, div).
|
||||
:- op(400, yfx, //).
|
||||
:- op(400, yfx, rdiv).
|
||||
:- op(400, yfx, <<).
|
||||
:- op(400, yfx, >>).
|
||||
:- op(400, yfx, mod).
|
||||
:- op(400, yfx, rem).
|
||||
:- op(200, fy, -).
|
||||
|
||||
% arithmetic comparison operators.
|
||||
:- op(700, xfx, >).
|
||||
:- op(700, xfx, <).
|
||||
:- op(700, xfx, =\=).
|
||||
:- op(700, xfx, =:=).
|
||||
:- op(700, xfx, >=).
|
||||
:- op(700, xfx, =<).
|
||||
|
||||
% control.
|
||||
:- op(700, xfx, =).
|
||||
:- op(900, fy, \+).
|
||||
:- op(700, xfx, =..).
|
||||
|
||||
% conditional operators.
|
||||
:- op(1050, xfy, ->).
|
||||
:- op(1100, xfy, ;).
|
||||
|
||||
% term comparison.
|
||||
:- op(700, xfx, ==).
|
||||
:- op(700, xfx, \==).
|
||||
:- op(700, xfx, @=<).
|
||||
:- op(700, xfx, @>=).
|
||||
:- op(700, xfx, @<).
|
||||
:- op(700, xfx, @>).
|
||||
:- op(700, xfx, =@=).
|
||||
:- op(700, xfx, \=@=).
|
||||
|
||||
% the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY).
|
||||
max_arity(63).
|
||||
|
||||
% unify.
|
||||
X = X.
|
||||
|
||||
true.
|
||||
|
||||
false :- '$fail'.
|
||||
|
||||
% control operators.
|
||||
|
||||
','(G1, G2) :- '$get_cp'(B), ','(G1, G2, B).
|
||||
|
||||
','(!, ','(G1, G2), B) :- '$set_cp'(B), ','(G1, G2, B).
|
||||
','(!, !, B) :- '$set_cp'(B).
|
||||
','(!, G, B) :- '$set_cp'(B), G.
|
||||
','(G, ','(G2, G3), B) :- !, G, ','(G2, G3, B).
|
||||
','(G, !, B) :- !, G, '$set_cp'(B).
|
||||
','(G1, G2, _) :- G1, G2.
|
||||
|
||||
;(G1, G2) :- '$get_cp'(B), ;(G1, G2, B).
|
||||
|
||||
;(G1, G4, B) :- compound(G1), G1 = ->(G2, G3), (G2 -> G3 ; '$set_cp'(B), G4).
|
||||
;(G1, G2, B) :- G1 == !, '$set_cp'(B), call(G2).
|
||||
;(G1, G2, B) :- G2 == !, call(G2), '$set_cp'(B).
|
||||
;(G, _, _) :- G.
|
||||
;(_, G, _) :- G.
|
||||
|
||||
G1 -> G2 :- '$get_cp'(B), ->(G1, G2, B).
|
||||
|
||||
->(G1, G2, B) :- G2 == !, call(G1), !, '$set_cp'(B).
|
||||
->(G1, G2, B) :- call(G1), '$set_cp'(B), call(G2).
|
||||
|
||||
% arg.
|
||||
|
||||
/* Here is the old, SWI Prolog-imitative arg/3. The new, ISO Prolog
|
||||
* compliant arg/3 is implemented in Rust.
|
||||
|
||||
arg(N, Functor, Arg) :- var(N), !, functor(Functor, _, Arity), arg_(N, 1, Arity, Functor, Arg).
|
||||
arg(N, Functor, Arg) :- integer(N), !, functor(Functor, _, Arity), '$get_arg'(N, Functor, Arg).
|
||||
arg(N, Functor, Arg) :- throw(error(type_error(integer, N), arg/3)).
|
||||
|
||||
arg_(N, N, N, Functor, Arg) :- !, '$get_arg'(N, Functor, Arg).
|
||||
arg_(N, N, Arity, Functor, Arg) :- '$get_arg'(N, Functor, Arg).
|
||||
arg_(N, N0, Arity, Functor, Arg) :- N0 < Arity, N1 is N0 + 1, arg_(N, N1, Arity, Functor, Arg).
|
||||
|
||||
*/
|
||||
|
||||
% univ.
|
||||
|
||||
\+ Goal :- call(Goal), !, false.
|
||||
\+ _.
|
||||
|
||||
univ_errors(Term, List, N) :-
|
||||
'$skip_max_list'(N, -1, List, R),
|
||||
( var(R) -> ( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||
; true )
|
||||
; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
|
||||
; List = [H|T] -> ( var(H), var(Term), % R == [] => List is a proper list.
|
||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 c)
|
||||
; T \== [], nonvar(H), \+ atom(H),
|
||||
throw(error(type_error(atom, H), (=..)/2)) % 8.5.3.3 d)
|
||||
; compound(H), T == [],
|
||||
throw(error(type_error(atomic, H), (=..)/2)) % 8.5.3.3 e)
|
||||
; var(Term), max_arity(M), N - 1 > M,
|
||||
throw(error(representation_error(max_arity), (=..)/2)) % 8.5.3.3 g)
|
||||
; true )
|
||||
; var(Term) -> throw(error(domain_error(non_empty_list, List), (=..)/2)) % 8.5.3.3 f)
|
||||
; true ).
|
||||
|
||||
Term =.. List :- univ_errors(Term, List, N), univ_worker(Term, List, N).
|
||||
|
||||
univ_worker(Term, List, _) :- atomic(Term), !, List = [Term].
|
||||
univ_worker(Term, [Name|Args], N) :-
|
||||
var(Term), !,
|
||||
Arity is N-1,
|
||||
functor(Term, Name, Arity),
|
||||
'$get_args'(Args, Term, 1, Arity).
|
||||
univ_worker(Term, List, _) :-
|
||||
functor(Term, Name, Arity),
|
||||
'$get_args'(Args, Term, 1, Arity),
|
||||
List = [Name|Args].
|
||||
|
||||
'$get_args'(Args, _, _, 0) :-
|
||||
!, Args = [].
|
||||
'$get_args'([Arg], Func, N, N) :-
|
||||
!, arg(N, Func, Arg).
|
||||
'$get_args'([Arg|Args], Func, I0, N) :-
|
||||
arg(I0, Func, Arg),
|
||||
I1 is I0 + 1,
|
||||
'$get_args'(Args, Func, I1, N).
|
||||
|
||||
% setup_call_cleanup.
|
||||
|
||||
/* past work on setup_call_cleanup.
|
||||
|
||||
setup_call_cleanup(S, G, C) :-
|
||||
S, !, '$get_current_block'(Bb),
|
||||
( var(C) -> throw(error(instantiation_error, setup_call_cleanup/3))
|
||||
; scc_helper(C, G, Bb) ).
|
||||
|
||||
scc_helper(C, G, Bb) :-
|
||||
'$get_level'(Cp), '$install_scc_cleaner'(C, NBb), call(G),
|
||||
( '$check_cp'(Cp) -> '$reset_block'(Bb), run_cleaners_without_handling(Cp)
|
||||
; true
|
||||
; '$reset_block'(NBb), '$fail').
|
||||
scc_helper(_, _, Bb) :-
|
||||
'$reset_block'(Bb), '$get_ball'(Ball),
|
||||
run_cleaners_with_handling, throw(Ball).
|
||||
scc_helper(_, _, _) :-
|
||||
run_cleaners_without_handling(Cp), false.
|
||||
|
||||
run_cleaners_with_handling :-
|
||||
'$get_scc_cleaner'(C), catch(C, _, true), !,
|
||||
run_cleaners_with_handling.
|
||||
run_cleaners_with_handling :-
|
||||
'$restore_cut_policy'.
|
||||
|
||||
run_cleaners_without_handling(Cp) :-
|
||||
'$get_scc_cleaner'(C), C, !, run_cleaners_without_handling(Cp).
|
||||
run_cleaners_without_handling(Cp) :-
|
||||
'$set_cp'(Cp), '$restore_cut_policy'.
|
||||
|
||||
*/
|
||||
|
||||
% exceptions.
|
||||
|
||||
catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb).
|
||||
|
||||
catch(G,C,R,Bb) :- '$install_new_block'(NBb), call(G), end_block(Bb, NBb).
|
||||
catch(G,C,R,Bb) :- '$reset_block'(Bb), '$get_ball'(Ball), handle_ball(Ball, C, R).
|
||||
|
||||
end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb).
|
||||
end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'.
|
||||
|
||||
handle_ball(Ball, C, R) :- Ball = C, !, '$erase_ball', call(R).
|
||||
handle_ball(_, _, _) :- '$unwind_stack'.
|
||||
|
||||
throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
|
||||
@@ -1,13 +1,19 @@
|
||||
:- module(control, [(\=)/2, between/3, call_cleanup/2, once/1, repeat/0]).
|
||||
:- use_module(library(builtins)).
|
||||
|
||||
:- module(control, [(\=)/2, (\+)/1, between/3, once/1, repeat/0]).
|
||||
|
||||
:- op(900, fy, \+).
|
||||
:- op(700, xfx, \=).
|
||||
|
||||
once(G) :- G, !.
|
||||
|
||||
\+ G :- G, !, false.
|
||||
\+ _.
|
||||
|
||||
X \= X :- !, false.
|
||||
_ \= _.
|
||||
|
||||
call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
||||
% call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
||||
|
||||
between(Lower, Upper, Lower) :-
|
||||
Lower =< Upper.
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
:- module(lists, [member/2, select/3, append/3, is_list/1, memberchk/2, reverse/2, maplist/2,
|
||||
maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8, maplist/9]).
|
||||
:- use_module(library(builtins)).
|
||||
|
||||
:- module(lists, [member/2, select/3, append/3, memberchk/2,
|
||||
reverse/2, length/2, maplist/2, maplist/3,
|
||||
maplist/4, maplist/5, maplist/6, maplist/7,
|
||||
maplist/8, maplist/9]).
|
||||
|
||||
length(Xs, N) :-
|
||||
var(N), !,
|
||||
'$skip_max_list'(M, -1, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> length_addendum(Xs0, N, M)).
|
||||
length(Xs, N) :-
|
||||
integer(N),
|
||||
N >= 0, !,
|
||||
'$skip_max_list'(M, N, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
|
||||
length(_, N) :-
|
||||
integer(N), !,
|
||||
throw(error(domain_error(not_less_than_zero, N), length/2)).
|
||||
length(_, N) :-
|
||||
throw(error(type_error(integer, N), length/2)).
|
||||
|
||||
length_addendum([], N, N).
|
||||
length_addendum([_|Xs], N, M) :-
|
||||
M1 is M + 1,
|
||||
length_addendum(Xs, N, M1).
|
||||
|
||||
length_rundown([], 0) :- !.
|
||||
length_rundown([_|Xs], N) :-
|
||||
N1 is N-1,
|
||||
length_rundown(Xs, N1).
|
||||
|
||||
member(X, [X|_]).
|
||||
member(X, [_|Xs]) :- member(X, Xs).
|
||||
@@ -10,10 +41,6 @@ select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
||||
append([], R, R).
|
||||
append([X|L], R, [X|S]) :- append(L, R, S).
|
||||
|
||||
is_list(X) :- var(X), !, false.
|
||||
is_list([]).
|
||||
is_list([_|T]) :- is_list(T).
|
||||
|
||||
memberchk(X, Xs) :- member(X, Xs), !.
|
||||
|
||||
reverse(Xs, Ys) :- reverse(Xs, [], Ys).
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
:- use_module(library(builtins)).
|
||||
|
||||
:- module(queues, [queue/1, queue/2, queue_head/3, queue_head_list/3,
|
||||
queue_last/3, queue_last_list/3, list_queue/2,
|
||||
queue_length/2]).
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
use prolog::num::bigint::BigInt;
|
||||
|
||||
@@ -8,6 +7,107 @@ use std::rc::Rc;
|
||||
pub(super) type MachineError = Vec<HeapCellValue>;
|
||||
pub(super) type MachineStub = Vec<HeapCellValue>;
|
||||
|
||||
// from 7.12.2 b) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ValidType {
|
||||
Atom,
|
||||
Atomic,
|
||||
// Byte,
|
||||
Callable,
|
||||
// Character,
|
||||
Compound,
|
||||
// Evaluable,
|
||||
// InByte,
|
||||
// InCharacter,
|
||||
Integer,
|
||||
List,
|
||||
// Number,
|
||||
Pair,
|
||||
// PredicateIndicator,
|
||||
// Variable
|
||||
}
|
||||
|
||||
impl ValidType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ValidType::Atom => "atom",
|
||||
ValidType::Atomic => "atomic",
|
||||
// ValidType::Byte => "byte",
|
||||
ValidType::Callable => "callable",
|
||||
// ValidType::Character => "character",
|
||||
ValidType::Compound => "compound",
|
||||
// ValidType::Evaluable => "evaluable",
|
||||
// ValidType::InByte => "in_byte",
|
||||
// ValidType::InCharacter => "in_character",
|
||||
ValidType::Integer => "integer",
|
||||
ValidType::List => "list",
|
||||
// ValidType::Number => "number",
|
||||
ValidType::Pair => "pair",
|
||||
// ValidType::PredicateIndicator => "predicate_indicator",
|
||||
// ValidType::Variable => "variable"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DomainError {
|
||||
NotLessThanZero
|
||||
}
|
||||
|
||||
impl DomainError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
DomainError::NotLessThanZero => "not_less_than_zero"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 f) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RepFlag {
|
||||
// Character,
|
||||
// CharacterCode,
|
||||
// InCharacterCode,
|
||||
MaxArity,
|
||||
// MaxInteger,
|
||||
// MinInteger
|
||||
}
|
||||
|
||||
impl RepFlag {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
// RepFlag::Character => "character",
|
||||
// RepFlag::CharacterCode => "character_code",
|
||||
// RepFlag::InCharacterCode => "in_character_code",
|
||||
RepFlag::MaxArity => "max_arity",
|
||||
// RepFlag::MaxInteger => "max_integer",
|
||||
// RepFlag::MinInteger => "min_integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 g) of 13211-1:1995
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum EvalError {
|
||||
// FloatOverflow,
|
||||
// IntOverflow,
|
||||
// Undefined,
|
||||
// Underflow,
|
||||
ZeroDivisor
|
||||
}
|
||||
|
||||
impl EvalError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
// EvalError::FloatOverflow => "float_overflow",
|
||||
// EvalError::IntOverflow => "int_overflow",
|
||||
// EvalError::Undefined => "undefined",
|
||||
// EvalError::Underflow => "underflow",
|
||||
EvalError::ZeroDivisor => "zero_divisor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// used by '$skip_max_list'.
|
||||
pub(super) enum CycleSearchResult {
|
||||
EmptyList,
|
||||
@@ -111,6 +211,10 @@ impl MachineState {
|
||||
error
|
||||
}
|
||||
|
||||
pub(super) fn domain_error(&self, error: DomainError, culprit: Addr) -> MachineError {
|
||||
functor!("domain_error", 2, [heap_atom!(error.as_str()), HeapCellValue::Addr(culprit)])
|
||||
}
|
||||
|
||||
pub(super) fn instantiation_error(&self) -> MachineError {
|
||||
functor!("instantiation_error")
|
||||
}
|
||||
@@ -125,7 +229,7 @@ impl MachineState {
|
||||
let mut error_form = vec![HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3 + err.len()))];
|
||||
|
||||
|
||||
error_form.extend(err.into_iter());
|
||||
error_form.extend(src.into_iter());
|
||||
|
||||
@@ -141,6 +245,8 @@ impl MachineState {
|
||||
self.heap.append(err);
|
||||
|
||||
self.registers[1] = Addr::HeapCell(h);
|
||||
self.goto_throw();
|
||||
|
||||
self.set_ball();
|
||||
self.unwind_stack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use prolog::and_stack::*;
|
||||
use prolog::ast::*;
|
||||
use prolog::copier::*;
|
||||
use prolog::machine::machine_errors::MachineStub;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||
use prolog::or_stack::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
use downcast::Any;
|
||||
@@ -17,14 +17,14 @@ use std::rc::Rc;
|
||||
|
||||
pub(super) struct Ball {
|
||||
pub(super) boundary: usize, // ball.0
|
||||
pub(super) stub: MachineStub, // ball.1
|
||||
pub(super) stub: MachineStub, // ball.1
|
||||
}
|
||||
|
||||
impl Ball {
|
||||
pub(super) fn new() -> Self {
|
||||
Ball { boundary: 0, stub: MachineStub::new() }
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn reset(&mut self) {
|
||||
self.boundary = 0;
|
||||
self.stub.clear();
|
||||
@@ -209,7 +209,7 @@ pub struct MachineState {
|
||||
pub(super) b0: usize,
|
||||
pub(super) e: usize,
|
||||
pub(super) num_of_args: usize,
|
||||
pub(super) cp: CodePtr,
|
||||
pub(super) cp: LocalCodePtr,
|
||||
pub(super) fail: bool,
|
||||
pub(crate) heap: Heap,
|
||||
pub(super) mode: MachineMode,
|
||||
@@ -222,61 +222,12 @@ pub struct MachineState {
|
||||
pub(super) block: usize, // an offset into the OR stack.
|
||||
pub(super) ball: Ball,
|
||||
pub(super) interms: Vec<Number>, // intermediate numbers.
|
||||
pub(super) last_call: bool
|
||||
}
|
||||
|
||||
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
||||
|
||||
pub(crate) trait CallPolicy: Any {
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex, lco: bool)
|
||||
-> CallResult
|
||||
{
|
||||
if lco {
|
||||
self.try_execute(machine_st, name, arity, idx)
|
||||
} else {
|
||||
self.try_call(machine_st, name, arity, idx)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
let b = machine_st.b - 1;
|
||||
@@ -400,49 +351,70 @@ pub(crate) trait CallPolicy: Any {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_call_clause<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
ct: &ClauseType, arity: usize, lco: bool)
|
||||
-> CallResult
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
||||
idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
if machine_st.last_call {
|
||||
self.try_execute(machine_st, name, arity, idx)
|
||||
} else {
|
||||
self.try_call(machine_st, name, arity, idx)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.cp.assign_if_local(machine_st.p.clone() + 1);
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = dir_entry!(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
match idx.0.borrow().0 {
|
||||
IndexPtr::Undefined =>
|
||||
return Err(machine_st.existence_error(name, arity)),
|
||||
IndexPtr::Index(compiled_tl_index) => {
|
||||
let module_name = idx.0.borrow().1.clone();
|
||||
|
||||
machine_st.num_of_args = arity;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = dir_entry!(compiled_tl_index, module_name);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
&ClauseType::AcyclicTerm => {
|
||||
&BuiltInClauseType::AcyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
machine_st.fail = machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Arg => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
|
||||
machine_st.num_of_args = 3;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(166, clause_name!("builtin"));
|
||||
|
||||
Ok(())
|
||||
&BuiltInClauseType::Arg => {
|
||||
machine_st.try_arg()?;
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Catch => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
|
||||
machine_st.num_of_args = 3;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::DirEntry(5, clause_name!("builtin"));
|
||||
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::CallN =>
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
if let Some(idx) = code_dirs.get(name.clone(), arity, clause_name!("user")) {
|
||||
self.context_call(machine_st, name, arity, idx, lco)
|
||||
} else {
|
||||
Err(machine_st.existence_error(name, arity))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Compare => {
|
||||
&BuiltInClauseType::Compare => {
|
||||
let a1 = machine_st[temp_v!(1)].clone();
|
||||
let a2 = machine_st[temp_v!(2)].clone();
|
||||
let a3 = machine_st[temp_v!(3)].clone();
|
||||
@@ -454,9 +426,9 @@ pub(crate) trait CallPolicy: Any {
|
||||
});
|
||||
|
||||
machine_st.unify(a1, c);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::CompareTerm(qt) => {
|
||||
&BuiltInClauseType::CompareTerm(qt) => {
|
||||
match qt {
|
||||
CompareTermQT::Equal =>
|
||||
machine_st.fail = machine_st.structural_eq_test(),
|
||||
@@ -465,47 +437,47 @@ pub(crate) trait CallPolicy: Any {
|
||||
_ => machine_st.compare_term(qt)
|
||||
};
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::CyclicTerm => {
|
||||
&BuiltInClauseType::CyclicTerm => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
machine_st.fail = !machine_st.is_cyclic_term(addr);
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Display => {
|
||||
&BuiltInClauseType::Display => {
|
||||
let output = machine_st.print_term(machine_st[temp_v!(1)].clone(),
|
||||
DisplayFormatter {},
|
||||
PrinterOutputter::new());
|
||||
|
||||
println!("{}", output.result());
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::DuplicateTerm => {
|
||||
&BuiltInClauseType::DuplicateTerm => {
|
||||
machine_st.duplicate_term();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Eq => {
|
||||
&BuiltInClauseType::Eq => {
|
||||
machine_st.fail = machine_st.eq_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Ground => {
|
||||
&BuiltInClauseType::Ground => {
|
||||
machine_st.fail = machine_st.ground_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Functor => {
|
||||
&BuiltInClauseType::Functor => {
|
||||
machine_st.try_functor()?;
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::NotEq => {
|
||||
&BuiltInClauseType::NotEq => {
|
||||
machine_st.fail = !machine_st.eq_test();
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Sort => {
|
||||
&BuiltInClauseType::Sort => {
|
||||
machine_st.check_sort_errors()?;
|
||||
|
||||
|
||||
let stub = machine_st.functor_stub(clause_name!("sort"), 2);
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
|
||||
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
|
||||
machine_st.term_dedup(&mut list);
|
||||
|
||||
@@ -514,15 +486,15 @@ pub(crate) trait CallPolicy: Any {
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::KeySort => {
|
||||
&BuiltInClauseType::KeySort => {
|
||||
machine_st.check_keysort_errors()?;
|
||||
|
||||
|
||||
let stub = machine_st.functor_stub(clause_name!("keysort"), 2);
|
||||
let mut list = machine_st.try_from_list(temp_v!(1), stub)?;
|
||||
let mut key_pairs = Vec::new();
|
||||
|
||||
let mut key_pairs = Vec::new();
|
||||
|
||||
for val in list {
|
||||
let key = machine_st.project_onto_key(val.clone())?;
|
||||
key_pairs.push((key, val.clone()));
|
||||
@@ -536,47 +508,100 @@ pub(crate) trait CallPolicy: Any {
|
||||
let r2 = machine_st[temp_v!(2)].clone();
|
||||
machine_st.unify(r2, heap_addr);
|
||||
|
||||
return_from_clause!(lco, machine_st)
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Throw => {
|
||||
if !lco {
|
||||
machine_st.cp = machine_st.p.clone() + 1;
|
||||
}
|
||||
&BuiltInClauseType::Is(r, ref at) => {
|
||||
let a1 = machine_st[r].clone();
|
||||
let a2 = machine_st.get_number(at)?;
|
||||
|
||||
machine_st.goto_throw();
|
||||
Ok(())
|
||||
machine_st.unify(a1, Addr::Con(Constant::Number(a2)));
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) =>
|
||||
self.context_call(machine_st, name.clone(), arity, idx.clone(), lco),
|
||||
&ClauseType::CallWithInferenceLimit => {
|
||||
machine_st.goto_ptr(CodePtr::DirEntry(409, clause_name!("builtin")), 3, lco);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::SetupCallCleanup => {
|
||||
machine_st.goto_ptr(CodePtr::DirEntry(310, clause_name!("builtin")), 3, lco);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Is => {
|
||||
let a = machine_st[temp_v!(1)].clone();
|
||||
let result = machine_st.arith_eval_by_metacall(temp_v!(2))?;
|
||||
|
||||
machine_st.unify(a, Addr::Con(Constant::Number(result)));
|
||||
machine_st.p += 1;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::Inlined(ref inlined) => {
|
||||
machine_st.execute_inlined(inlined, &vec![temp_v!(1), temp_v!(2)]);
|
||||
Ok(())
|
||||
},
|
||||
&ClauseType::SkipMaxList => {
|
||||
machine_st.skip_max_list()?;
|
||||
machine_st.p += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
||||
-> CallResult
|
||||
{
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
let user = clause_name!("user");
|
||||
|
||||
match ClauseType::from(name.clone(), arity, None) {
|
||||
ClauseType::CallN => {
|
||||
machine_st.handle_internal_call_n(arity);
|
||||
|
||||
if machine_st.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
machine_st.p = CodePtr::CallN(arity, machine_st.p.local());
|
||||
},
|
||||
ClauseType::BuiltIn(built_in) =>
|
||||
machine_st.setup_built_in_call(built_in),
|
||||
ClauseType::Inlined(inlined) =>
|
||||
machine_st.execute_inlined(&inlined),
|
||||
ClauseType::Op(..) | ClauseType::Named(..) =>
|
||||
if let Some(idx) = code_dirs.get(name.clone(), arity, user) {
|
||||
self.context_call(machine_st, name, arity, idx)?;
|
||||
} else {
|
||||
return Err(machine_st.existence_error(name, arity));
|
||||
},
|
||||
ClauseType::System(_) =>
|
||||
return Err(machine_st.type_error(ValidType::Callable,
|
||||
Addr::Con(Constant::Atom(name))))
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
||||
fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||
arity: usize, idx: CodeIndex)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.context_call(machine_st, name, arity, idx)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.retry_me_else(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.retry(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
|
||||
{
|
||||
self.prev_policy.trust_me(machine_st)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.trust(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.call_builtin(machine_st, ct)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize, code_dirs: CodeDirs<'a>)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.call_n(machine_st, arity, code_dirs)?;
|
||||
self.increment()
|
||||
}
|
||||
}
|
||||
|
||||
downcast!(CallPolicy);
|
||||
@@ -651,40 +676,6 @@ impl CallWithInferenceLimitCallPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
impl CallPolicy for CallWithInferenceLimitCallPolicy {
|
||||
fn retry_me_else(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.retry_me_else(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn retry(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.retry(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn trust_me(&mut self, machine_st: &mut MachineState) -> CallResult
|
||||
{
|
||||
self.prev_policy.trust_me(machine_st)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn trust(&mut self, machine_st: &mut MachineState, offset: usize) -> CallResult
|
||||
{
|
||||
self.prev_policy.trust(machine_st, offset)?;
|
||||
self.increment()
|
||||
}
|
||||
|
||||
fn try_call_clause<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
|
||||
ct: &ClauseType, arity: usize, lco: bool)
|
||||
-> CallResult
|
||||
{
|
||||
self.prev_policy.try_call_clause(machine_st, code_dirs, ct, arity, lco)?;
|
||||
self.increment()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait CutPolicy: Any {
|
||||
fn cut(&mut self, &mut MachineState, RegType);
|
||||
}
|
||||
@@ -707,27 +698,25 @@ impl CutPolicy for DefaultCutPolicy {
|
||||
machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
|
||||
machine_st.p += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SetupCallCleanupCutPolicy {
|
||||
pub(crate) struct SCCCutPolicy {
|
||||
// locations of cleaners, cut points, the previous block
|
||||
cont_pts: Vec<(Addr, usize, usize)>
|
||||
}
|
||||
|
||||
impl SetupCallCleanupCutPolicy {
|
||||
impl SCCCutPolicy {
|
||||
pub(crate) fn new() -> Self {
|
||||
SetupCallCleanupCutPolicy { cont_pts: vec![] }
|
||||
SCCCutPolicy { cont_pts: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn out_of_cont_pts(&self) -> bool {
|
||||
self.cont_pts.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, block: usize) {
|
||||
self.cont_pts.push((addr, b, block));
|
||||
pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, prev_b: usize) {
|
||||
self.cont_pts.push((addr, b, prev_b));
|
||||
}
|
||||
|
||||
pub(crate) fn pop_cont_pt(&mut self) -> Option<(Addr, usize, usize)> {
|
||||
@@ -735,12 +724,12 @@ impl SetupCallCleanupCutPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
impl CutPolicy for SetupCallCleanupCutPolicy {
|
||||
impl CutPolicy for SCCCutPolicy {
|
||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) {
|
||||
let b = machine_st.b;
|
||||
|
||||
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
|
||||
if b > b0 {
|
||||
if b > b0 {
|
||||
machine_st.b = b0;
|
||||
machine_st.tidy_trail();
|
||||
machine_st.or_stack.truncate(machine_st.b);
|
||||
@@ -748,16 +737,13 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
|
||||
} else {
|
||||
machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
|
||||
machine_st.p += 1;
|
||||
|
||||
if !self.out_of_cont_pts() {
|
||||
machine_st.cp = machine_st.p.clone();
|
||||
machine_st.num_of_args = 0;
|
||||
machine_st.b0 = machine_st.b;
|
||||
// goto_call run_cleaners_without_handling/0, 370.
|
||||
machine_st.p = CodePtr::DirEntry(370, clause_name!("builtin"));
|
||||
}
|
||||
|
||||
if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() {
|
||||
if machine_st.b < b_cutoff {
|
||||
machine_st.block = prev_block;
|
||||
machine_st.unwind_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::compile::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::tabled_rc::*;
|
||||
|
||||
@@ -7,6 +7,7 @@ mod machine_errors;
|
||||
pub(super) mod machine_state;
|
||||
#[macro_use]
|
||||
mod machine_state_impl;
|
||||
mod system_calls;
|
||||
|
||||
use prolog::machine::machine_state::*;
|
||||
|
||||
@@ -16,9 +17,9 @@ use std::mem::swap;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) struct MachineCodeIndex<'a> {
|
||||
pub(super) code_dir: &'a mut CodeDir,
|
||||
pub(super) op_dir: &'a mut OpDir,
|
||||
pub struct MachineCodeIndex<'a> {
|
||||
pub code_dir: &'a mut CodeDir,
|
||||
pub op_dir: &'a mut OpDir,
|
||||
}
|
||||
|
||||
pub struct Machine {
|
||||
@@ -33,18 +34,18 @@ pub struct Machine {
|
||||
cached_query: Option<Code>
|
||||
}
|
||||
|
||||
impl Index<CodePtr> for Machine {
|
||||
impl Index<LocalCodePtr> for Machine {
|
||||
type Output = Line;
|
||||
|
||||
fn index(&self, ptr: CodePtr) -> &Self::Output {
|
||||
fn index(&self, ptr: LocalCodePtr) -> &Self::Output {
|
||||
match ptr {
|
||||
CodePtr::TopLevel(_, p) => {
|
||||
LocalCodePtr::TopLevel(_, p) => {
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => &cq[p],
|
||||
&None => panic!("Out-of-bounds top level index.")
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
LocalCodePtr::DirEntry(p, _) => &self.code[p]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,23 +66,33 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> {
|
||||
self.code_dir.insert((name, arity), CodeIndex::from(idx));
|
||||
}
|
||||
}
|
||||
|
||||
static LISTS: &str = include_str!("../lib/lists.pl");
|
||||
static CONTROL: &str = include_str!("../lib/control.pl");
|
||||
static QUEUES: &str = include_str!("../lib/queues.pl");
|
||||
|
||||
impl Machine {
|
||||
pub fn new() -> Self {
|
||||
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
|
||||
let (code, code_dir, op_dir) = default_build();
|
||||
|
||||
Machine {
|
||||
ms: MachineState::new(atom_tbl),
|
||||
let mut wam = Machine {
|
||||
ms: MachineState::new(Rc::new(RefCell::new(HashSet::new()))),
|
||||
call_policy: Box::new(DefaultCallPolicy {}),
|
||||
cut_policy: Box::new(DefaultCutPolicy {}),
|
||||
code,
|
||||
code_dir,
|
||||
code: Code::new(),
|
||||
code_dir: CodeDir::new(),
|
||||
term_dir: TermDir::new(),
|
||||
op_dir,
|
||||
op_dir: default_op_dir(),
|
||||
modules: HashMap::new(),
|
||||
cached_query: None
|
||||
}
|
||||
};
|
||||
|
||||
compile_listing(&mut wam, BUILTINS);
|
||||
wam.use_module_in_toplevel(clause_name!("builtins"));
|
||||
|
||||
compile_listing(&mut wam, LISTS);
|
||||
compile_listing(&mut wam, CONTROL);
|
||||
compile_listing(&mut wam, QUEUES);
|
||||
|
||||
wam
|
||||
}
|
||||
|
||||
fn remove_module(&mut self, module_name: ClauseName) {
|
||||
@@ -221,36 +232,43 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_instr(&self, p: CodePtr) -> Option<Line> {
|
||||
match p {
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) =>
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => Some(cq[p].clone()),
|
||||
&None => None
|
||||
},
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p, _)) =>
|
||||
Some(self.code[p].clone()),
|
||||
CodePtr::BuiltInClause(built_in, _) =>
|
||||
Some(call_clause!(ClauseType::BuiltIn(built_in.clone()), built_in.arity(),
|
||||
0, self.ms.last_call)),
|
||||
CodePtr::CallN(arity, _) =>
|
||||
Some(call_clause!(ClauseType::CallN, arity, 0, self.ms.last_call))
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_instr(&mut self)
|
||||
{
|
||||
let instr = match self.ms.p {
|
||||
CodePtr::TopLevel(_, p) => {
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => &cq[p],
|
||||
&None => return
|
||||
}
|
||||
},
|
||||
CodePtr::DirEntry(p, _) => &self.code[p]
|
||||
let instr = match self.lookup_instr(self.ms.p.clone()) {
|
||||
Some(instr) => instr,
|
||||
None => return
|
||||
};
|
||||
|
||||
match instr {
|
||||
&Line::Arithmetic(ref arith_instr) =>
|
||||
Line::Arithmetic(ref arith_instr) =>
|
||||
self.ms.execute_arith_instr(arith_instr),
|
||||
&Line::BuiltIn(ref built_in_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_built_in_instr(code_dirs, &mut self.call_policy,
|
||||
&mut self.cut_policy, built_in_instr);
|
||||
},
|
||||
&Line::Choice(ref choice_instr) =>
|
||||
Line::Choice(ref choice_instr) =>
|
||||
self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
|
||||
&Line::Cut(ref cut_instr) =>
|
||||
Line::Cut(ref cut_instr) =>
|
||||
self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
|
||||
&Line::Control(ref control_instr) => {
|
||||
Line::Control(ref control_instr) => {
|
||||
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
|
||||
self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy,
|
||||
&mut self.cut_policy, control_instr)
|
||||
},
|
||||
&Line::Fact(ref fact) => {
|
||||
Line::Fact(ref fact) => {
|
||||
for fact_instr in fact {
|
||||
if self.failed() {
|
||||
break;
|
||||
@@ -261,11 +279,11 @@ impl Machine {
|
||||
|
||||
self.ms.p += 1;
|
||||
},
|
||||
&Line::Indexing(ref indexing_instr) =>
|
||||
Line::Indexing(ref indexing_instr) =>
|
||||
self.ms.execute_indexing_instr(&indexing_instr),
|
||||
&Line::IndexedChoice(ref choice_instr) =>
|
||||
Line::IndexedChoice(ref choice_instr) =>
|
||||
self.ms.execute_indexed_choice_instr(choice_instr, &mut self.call_policy),
|
||||
&Line::Query(ref query) => {
|
||||
Line::Query(ref query) => {
|
||||
for query_instr in query {
|
||||
if self.failed() {
|
||||
break;
|
||||
@@ -287,13 +305,13 @@ impl Machine {
|
||||
self.ms.b0 = self.ms.or_stack[b].b0;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, p) = self.ms.p {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.ms.p {
|
||||
self.ms.fail = p == 0;
|
||||
} else {
|
||||
self.ms.fail = false;
|
||||
}
|
||||
} else {
|
||||
self.ms.p = CodePtr::TopLevel(0, 0);
|
||||
self.ms.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,8 +325,9 @@ impl Machine {
|
||||
}
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::DirEntry(p, _) if p < self.code.len() => {},
|
||||
_ => break
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p, _)) if p < self.code.len() => {},
|
||||
CodePtr::Local(_) => break,
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -340,11 +359,11 @@ impl Machine {
|
||||
|
||||
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
|
||||
let end_ptr = top_level_code_ptr!(0, self.cached_query_size());
|
||||
|
||||
while self.ms.p < end_ptr {
|
||||
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
|
||||
match &self[CodePtr::TopLevel(cn, p)] {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.ms.p {
|
||||
match &self[LocalCodePtr::TopLevel(cn, p)] {
|
||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
||||
cn += 1;
|
||||
@@ -352,13 +371,13 @@ impl Machine {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.ms.p = CodePtr::TopLevel(cn, p);
|
||||
self.ms.p = top_level_code_ptr!(cn, p);
|
||||
}
|
||||
|
||||
self.query_stepper();
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::TopLevel(_, p) if p > 0 => {},
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
|
||||
_ => {
|
||||
if heap_locs.is_empty() {
|
||||
self.record_var_places(0, alloc_locs, heap_locs);
|
||||
@@ -375,7 +394,7 @@ impl Machine {
|
||||
if self.ms.ball.stub.len() > 0 {
|
||||
let h = self.ms.heap.h;
|
||||
self.ms.copy_and_align_ball_to_heap();
|
||||
|
||||
|
||||
let error_str = self.ms.print_exception(Addr::HeapCell(h),
|
||||
&heap_locs,
|
||||
TermFormatter {},
|
||||
@@ -408,7 +427,7 @@ impl Machine {
|
||||
let b = self.ms.b - 1;
|
||||
self.ms.p = self.ms.or_stack[b].bp.clone();
|
||||
|
||||
if let CodePtr::TopLevel(_, 0) = self.ms.p {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.ms.p {
|
||||
return EvalSession::from(SessionError::QueryFailure);
|
||||
}
|
||||
|
||||
|
||||
379
src/prolog/machine/system_calls.rs
Normal file
379
src/prolog/machine/system_calls.rs
Normal file
@@ -0,0 +1,379 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
use prolog::num::{ToPrimitive, Zero};
|
||||
use prolog::num::bigint::BigInt;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
struct BrentAlgState {
|
||||
hare: usize,
|
||||
tortoise: usize,
|
||||
power: usize,
|
||||
steps: usize
|
||||
}
|
||||
|
||||
impl BrentAlgState {
|
||||
fn new(hare: usize) -> Self {
|
||||
BrentAlgState { hare, tortoise: hare, power: 2, steps: 1 }
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
// a step in Brent's algorithm.
|
||||
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
|
||||
{
|
||||
match self.heap[brent_st.hare].clone() {
|
||||
HeapCellValue::Addr(Addr::Lis(l)) => {
|
||||
brent_st.hare = l + 1;
|
||||
brent_st.steps += 1;
|
||||
|
||||
if brent_st.tortoise == brent_st.hare {
|
||||
return Some(CycleSearchResult::NotList);
|
||||
} else if brent_st.steps == brent_st.power {
|
||||
brent_st.tortoise = brent_st.hare;
|
||||
brent_st.power <<= 1;
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
HeapCellValue::NamedStr(..) =>
|
||||
Some(CycleSearchResult::NotList),
|
||||
HeapCellValue::Addr(addr) =>
|
||||
match self.store(self.deref(addr)) {
|
||||
Addr::Con(Constant::EmptyList) =>
|
||||
Some(CycleSearchResult::ProperList(brent_st.steps)),
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
|
||||
_ =>
|
||||
Some(CycleSearchResult::NotList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
|
||||
{
|
||||
let addr = self.store(self.deref(addr));
|
||||
let hare = match addr {
|
||||
Addr::Lis(offset) if max_steps > 0 => offset + 1,
|
||||
Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
|
||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
let mut brent_st = BrentAlgState::new(hare);
|
||||
|
||||
loop {
|
||||
if brent_st.steps == max_steps {
|
||||
return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare);
|
||||
}
|
||||
|
||||
if let Some(result) = self.brents_alg_step(&mut brent_st) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult
|
||||
{
|
||||
let addr = self.store(self.deref(addr));
|
||||
let hare = match addr {
|
||||
Addr::Lis(offset) => offset + 1,
|
||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
let mut brent_st = BrentAlgState::new(hare);
|
||||
|
||||
loop {
|
||||
if let Some(result) = self.brents_alg_step(&mut brent_st) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) {
|
||||
let target_n = self[temp_v!(1)].clone();
|
||||
self.unify(Addr::Con(integer!(n)), target_n);
|
||||
|
||||
if !self.fail {
|
||||
let xs = self[temp_v!(4)].clone();
|
||||
self.unify(addr, xs);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn skip_max_list(&mut self) -> Result<(), MachineError> {
|
||||
let max_steps = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match max_steps {
|
||||
Addr::Con(Constant::Number(Number::Integer(ref max_steps)))
|
||||
if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) => {
|
||||
let n = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match n {
|
||||
Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => {
|
||||
let xs0 = self[temp_v!(3)].clone();
|
||||
let xs = self[temp_v!(4)].clone();
|
||||
|
||||
self.unify(xs0, xs);
|
||||
},
|
||||
_ => {
|
||||
let search_result = if let Some(max_steps) = max_steps.to_isize() {
|
||||
if max_steps == -1 {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
} else {
|
||||
self.detect_cycles_with_max(max_steps as usize,
|
||||
self[temp_v!(3)].clone())
|
||||
}
|
||||
} else {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
};
|
||||
|
||||
match search_result {
|
||||
CycleSearchResult::UntouchedList(l) =>
|
||||
self.finalize_skip_max_list(0, Addr::Lis(l)),
|
||||
CycleSearchResult::EmptyList =>
|
||||
self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)),
|
||||
CycleSearchResult::PartialList(n, hc) =>
|
||||
self.finalize_skip_max_list(n, Addr::HeapCell(hc)),
|
||||
CycleSearchResult::ProperList(n) =>
|
||||
self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)),
|
||||
CycleSearchResult::NotList => {
|
||||
let xs0 = self[temp_v!(3)].clone();
|
||||
self.finalize_skip_max_list(0, xs0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn install_new_block(&mut self, r: RegType) -> usize {
|
||||
self.block = self.b;
|
||||
|
||||
let c = Constant::Usize(self.block);
|
||||
let addr = self[r].clone();
|
||||
|
||||
self.write_constant_to_var(addr, c);
|
||||
self.block
|
||||
}
|
||||
|
||||
pub(super) fn system_call(&mut self, ct: &SystemClauseType,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
&SystemClauseType::CheckCutPoint => {
|
||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match addr {
|
||||
Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::GetSCCCleaner => {
|
||||
let dest = self[temp_v!(1)].clone();
|
||||
|
||||
match cut_policy.downcast_mut::<SCCCutPolicy>().ok() {
|
||||
Some(sgc_policy) =>
|
||||
if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() {
|
||||
if self.b <= b_cutoff + 1 {
|
||||
self.block = prev_b;
|
||||
|
||||
if let Some(r) = dest.as_var() {
|
||||
self.bind(r, addr.clone());
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
sgc_policy.push_cont_pt(addr, b_cutoff, prev_b);
|
||||
}
|
||||
},
|
||||
None => panic!("expected SCCCutPolicy trait object.")
|
||||
};
|
||||
|
||||
self.fail = true;
|
||||
},
|
||||
&SystemClauseType::InstallSCCCleaner => {
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
let b = self.b;
|
||||
let prev_block = self.block;
|
||||
|
||||
if cut_policy.downcast_ref::<SCCCutPolicy>().is_err() {
|
||||
*cut_policy = Box::new(SCCCutPolicy::new());
|
||||
}
|
||||
|
||||
match cut_policy.downcast_mut::<SCCCutPolicy>().ok()
|
||||
{
|
||||
Some(cut_policy) => {
|
||||
self.install_new_block(temp_v!(2));
|
||||
cut_policy.push_cont_pt(addr, b, prev_block);
|
||||
},
|
||||
None => panic!("install_cleaner: should have installed \\
|
||||
SCCCutPolicy.")
|
||||
};
|
||||
},
|
||||
&SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L
|
||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
if call_policy.downcast_ref::<CallWithInferenceLimitCallPolicy>().is_err() {
|
||||
CallWithInferenceLimitCallPolicy::new_in_place(call_policy);
|
||||
}
|
||||
|
||||
match (a1, a2.clone()) {
|
||||
(Addr::Con(Constant::Usize(bp)),
|
||||
Addr::Con(Constant::Number(Number::Integer(n)))) =>
|
||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
||||
Some(call_policy) => {
|
||||
let count = call_policy.add_limit(n, bp);
|
||||
self[temp_v!(3)] = Addr::Con(Constant::Number(Number::Integer(count)));
|
||||
},
|
||||
None => panic!("install_inference_counter: should have installed \\
|
||||
CallWithInferenceLimitCallPolicy.")
|
||||
},
|
||||
_ => {
|
||||
let stub = self.functor_stub(clause_name!("call_with_inference_limit"), 3);
|
||||
let type_error = self.error_form(self.type_error(ValidType::Integer, a2),
|
||||
stub);
|
||||
self.throw_exception(type_error)
|
||||
}
|
||||
};
|
||||
},
|
||||
&SystemClauseType::RemoveCallPolicyCheck => {
|
||||
let restore_default =
|
||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
||||
Some(call_policy) => {
|
||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
||||
if call_policy.is_empty() && bp == self.b {
|
||||
Some(call_policy.into_inner())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
panic!("remove_call_policy_check: expected Usize in A1.");
|
||||
}
|
||||
},
|
||||
None => panic!("remove_call_policy_check: requires \\
|
||||
CallWithInferenceLimitCallPolicy.")
|
||||
};
|
||||
|
||||
if let Some(new_policy) = restore_default {
|
||||
*call_policy = new_policy;
|
||||
}
|
||||
},
|
||||
&SystemClauseType::RemoveInferenceCounter => {
|
||||
match call_policy.downcast_mut::<CallWithInferenceLimitCallPolicy>().ok() {
|
||||
Some(call_policy) => {
|
||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
||||
let count = call_policy.remove_limit(bp);
|
||||
self[temp_v!(2)] = Addr::Con(Constant::Number(Number::Integer(count)));
|
||||
} else {
|
||||
panic!("remove_inference_counter: expected Usize in A1.");
|
||||
}
|
||||
},
|
||||
None => panic!("remove_inference_counters: requires \\
|
||||
CallWithInferenceLimitCallPolicy.")
|
||||
};
|
||||
},
|
||||
&SystemClauseType::RestoreCutPolicy => {
|
||||
let restore_default =
|
||||
if let Ok(cut_policy) = cut_policy.downcast_ref::<SCCCutPolicy>() {
|
||||
cut_policy.out_of_cont_pts()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if restore_default {
|
||||
*cut_policy = Box::new(DefaultCutPolicy {});
|
||||
}
|
||||
},
|
||||
&SystemClauseType::SetCutPoint(r) =>
|
||||
cut_policy.cut(self, r),
|
||||
&SystemClauseType::InferenceLevel => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match a2 {
|
||||
Addr::Con(Constant::Usize(bp)) =>
|
||||
if self.b <= bp + 1 {
|
||||
let a2 = Addr::Con(atom!("!"));
|
||||
self.unify(a1, a2);
|
||||
} else {
|
||||
let a2 = Addr::Con(atom!("true"));
|
||||
self.unify(a1, a2);
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::CleanUpBlock => {
|
||||
let nb = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
|
||||
match nb {
|
||||
Addr::Con(Constant::Usize(nb)) => {
|
||||
let b = self.b - 1;
|
||||
|
||||
if nb > 0 && self.or_stack[b].b == nb {
|
||||
self.b = self.or_stack[nb - 1].b;
|
||||
self.or_stack.truncate(self.b);
|
||||
}
|
||||
},
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::EraseBall => self.ball.reset(),
|
||||
&SystemClauseType::Fail => self.fail = true,
|
||||
&SystemClauseType::GetBall => {
|
||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let h = self.heap.h;
|
||||
|
||||
if self.ball.stub.len() > 0 {
|
||||
self.copy_and_align_ball_to_heap();
|
||||
} else {
|
||||
self.fail = true;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ball = self.heap[h].as_addr(h);
|
||||
|
||||
match addr.as_var() {
|
||||
Some(r) => self.bind(r, ball),
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::GetCurrentBlock => {
|
||||
let c = Constant::Usize(self.block);
|
||||
let addr = self[temp_v!(1)].clone();
|
||||
|
||||
self.write_constant_to_var(addr, c);
|
||||
},
|
||||
&SystemClauseType::GetCutPoint => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
let a2 = Addr::Con(Constant::Usize(self.b));
|
||||
|
||||
self.unify(a1, a2);
|
||||
},
|
||||
&SystemClauseType::InstallNewBlock => {
|
||||
self.install_new_block(temp_v!(1));
|
||||
},
|
||||
&SystemClauseType::ResetBlock => {
|
||||
let addr = self.deref(self[temp_v!(1)].clone());
|
||||
self.reset_block(addr);
|
||||
},
|
||||
&SystemClauseType::SetBall => self.set_ball(),
|
||||
&SystemClauseType::SkipMaxList => return self.skip_max_list(),
|
||||
&SystemClauseType::Succeed => {},
|
||||
&SystemClauseType::UnwindStack => self.unwind_stack()
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -19,30 +19,6 @@ macro_rules! atom {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! internal_call_n {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::InternalCallN)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! allocate {
|
||||
($cells:expr) => (
|
||||
Line::Control(ControlInstruction::Allocate($cells))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! deallocate {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::Deallocate)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! compare_number_instr {
|
||||
($cmp: expr, $at_1: expr, $at_2: expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CompareNumber($cmp, $at_1, $at_2))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! interm {
|
||||
($n: expr) => (
|
||||
ArithmeticTerm::Interm($n)
|
||||
@@ -88,12 +64,6 @@ macro_rules! functor {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! fact {
|
||||
[$($x:expr),+] => (
|
||||
Line::Fact(vec![$($x),+])
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! temp_v {
|
||||
($x:expr) => (
|
||||
RegType::Temp($x)
|
||||
@@ -106,169 +76,68 @@ macro_rules! perm_v {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_var_in_query {
|
||||
($r:expr, $arg:expr) => (
|
||||
QueryInstruction::GetVariable($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
macro_rules! get_value {
|
||||
($r:expr, $arg:expr) => (
|
||||
FactInstruction::GetValue($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_void {
|
||||
($n:expr) => (
|
||||
QueryInstruction::SetVoid($n)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_value {
|
||||
($r:expr) => (
|
||||
QueryInstruction::SetValue($r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_var_in_fact {
|
||||
($r:expr, $arg:expr) => (
|
||||
FactInstruction::GetVariable($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_var {
|
||||
($r:expr, $arg:expr) => (
|
||||
QueryInstruction::PutVariable($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_structure {
|
||||
($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => (
|
||||
QueryInstruction::PutStructure(ClauseType::Op(clause_name!($atom), $fix, CodeIndex::default()),
|
||||
$arity,
|
||||
$r)
|
||||
);
|
||||
($atom:expr, $arity:expr, $r:expr, None) => (
|
||||
QueryInstruction::PutStructure(ClauseType::Named(clause_name!($atom), CodeIndex::default()),
|
||||
$arity,
|
||||
$r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_constant {
|
||||
($lvl:expr, $cons:expr, $r:expr) => (
|
||||
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_constant {
|
||||
($cons:expr) => (
|
||||
QueryInstruction::SetConstant($cons)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_value {
|
||||
($r:expr, $arg:expr) => (
|
||||
QueryInstruction::PutValue($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_unsafe_value {
|
||||
($r:expr, $arg:expr) => (
|
||||
QueryInstruction::PutUnsafeValue($r, $arg)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! try_me_else {
|
||||
($o:expr) => (
|
||||
Line::Choice(ChoiceInstruction::TryMeElse($o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! retry_me_else {
|
||||
($o:expr) => (
|
||||
Line::Choice(ChoiceInstruction::RetryMeElse($o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_atom {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsAtom, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_atomic {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsAtomic, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_integer {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsInteger, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_compound {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsCompound, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_float {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsFloat, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_rational {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsRational, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
macro_rules! is_nonvar {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsNonVar, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_string {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsString, vec![$r]))
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsString($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_var {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::IsVar, vec![$r]))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! trust_me {
|
||||
() => (
|
||||
Line::Choice(ChoiceInstruction::TrustMe)
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! call_clause {
|
||||
($ct:expr, $arity:expr, $pvs:expr) => (
|
||||
Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! call_n {
|
||||
($arity:expr) => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::CallN, $arity, 0, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! execute_n {
|
||||
($arity:expr) => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::CallN, $arity, 0, true))
|
||||
)
|
||||
);
|
||||
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => (
|
||||
Line::Control(ControlInstruction::CallClause($ct, $arity, $pvs, $lco))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! proceed {
|
||||
@@ -277,197 +146,15 @@ macro_rules! proceed {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cut {
|
||||
($r:expr) => (
|
||||
Line::Cut(CutInstruction::Cut($r))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! neck_cut {
|
||||
() => (
|
||||
Line::Cut(CutInstruction::NeckCut)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_current_block {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::GetCurrentBlock)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! install_new_block {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::InstallNewBlock)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! goto_call {
|
||||
($line:expr, $arity:expr) => (
|
||||
Line::Control(ControlInstruction::Goto($line, $arity, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! goto_execute {
|
||||
($line:expr, $arity:expr) => (
|
||||
Line::Control(ControlInstruction::Goto($line, $arity, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! reset_block {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::ResetBlock)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_ball {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::GetBall)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! erase_ball {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::EraseBall)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unify {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::Unify)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! is_call {
|
||||
($r:expr, $at:expr) => (
|
||||
Line::Control(ControlInstruction::IsClause(false, $r, $at))
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unwind_stack {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::UnwindStack)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! clean_up_block {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::CleanUpBlock)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_ball {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::SetBall)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! fail {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::Fail)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! succeed {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::Succeed)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! duplicate_term {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::DuplicateTerm, 2, 0, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_level {
|
||||
($r:expr) => (
|
||||
Line::Cut(CutInstruction::GetLevel($r))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! switch_on_term {
|
||||
($v:expr, $c:expr, $l:expr, $s:expr) => (
|
||||
Line::Indexing(IndexingInstruction::SwitchOnTerm($v, $c, $l, $s))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! indexed_try {
|
||||
($i:expr) => (
|
||||
Line::IndexedChoice(IndexedChoiceInstruction::Try($i))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! retry {
|
||||
($i:expr) => (
|
||||
Line::IndexedChoice(IndexedChoiceInstruction::Retry($i))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! trust {
|
||||
($i:expr) => (
|
||||
Line::IndexedChoice(IndexedChoiceInstruction::Trust($i))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_constant {
|
||||
($c:expr, $r:expr) => (
|
||||
FactInstruction::GetConstant(Level::Shallow, $c, $r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_structure {
|
||||
($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => (
|
||||
FactInstruction::GetStructure(ClauseType::Op(clause_name!($atom), $fix, CodeIndex::default()),
|
||||
$arity,
|
||||
$r)
|
||||
);
|
||||
($atom:expr, $arity:expr, $r:expr, None) => (
|
||||
FactInstruction::GetStructure(ClauseType::Named(clause_name!($atom), CodeIndex::default()),
|
||||
$arity,
|
||||
$r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! functor_call {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Functor, 3, 0, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! functor_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Functor, 3, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unify_value {
|
||||
($r:expr) => (
|
||||
FactInstruction::UnifyValue($r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unify_variable {
|
||||
($r:expr) => (
|
||||
FactInstruction::UnifyVariable($r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unify_void {
|
||||
($n:expr) => (
|
||||
FactInstruction::UnifyVoid($n)
|
||||
call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_cp {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::SetCutPoint($r))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_cp {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::GetCutPoint($r))
|
||||
call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -477,101 +164,29 @@ macro_rules! integer {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! add {
|
||||
($at_1:expr, $at_2:expr, $o:expr) => (
|
||||
Line::Arithmetic(ArithmeticInstruction::Add($at_1, $at_2, $o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! sub {
|
||||
($at_1:expr, $at_2:expr, $o:expr) => (
|
||||
Line::Arithmetic(ArithmeticInstruction::Sub($at_1, $at_2, $o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_arg_call {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::GetArg(false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_arg_execute {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::GetArg(true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! rc_integer {
|
||||
($e:expr) => (
|
||||
Number::Integer(Rc::new(BigInt::from($e)))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! rc_atom {
|
||||
($e:expr) => (
|
||||
Rc::new(String::from($e))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! infix {
|
||||
macro_rules! succeed {
|
||||
() => (
|
||||
Fixity::In
|
||||
call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! display {
|
||||
macro_rules! fail {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Display, 1, 0, false))
|
||||
call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! dynamic_is {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Is, 2, 0, false))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! dynamic_num_test {
|
||||
($cmp:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::CallInlined(InlinedClauseType::CompareNumber($cmp),
|
||||
vec![temp_v!(1), temp_v!(2)]))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_gt {
|
||||
() => (
|
||||
CompareNumberQT::GreaterThan
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_lt {
|
||||
() => (
|
||||
CompareNumberQT::LessThan
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_gte {
|
||||
() => (
|
||||
CompareNumberQT::GreaterThanOrEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_lte {
|
||||
() => (
|
||||
CompareNumberQT::LessThanOrEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_ne {
|
||||
() => (
|
||||
CompareNumberQT::NotEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cmp_eq {
|
||||
() => (
|
||||
CompareNumberQT::Equal
|
||||
)
|
||||
macro_rules! compare_number_instr {
|
||||
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
||||
let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
|
||||
call_clause!(ct, 2, 0)
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! jmp_call {
|
||||
@@ -580,162 +195,6 @@ macro_rules! jmp_call {
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! jmp_execute {
|
||||
($arity:expr, $offset:expr, $pvs:expr) => (
|
||||
Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_list {
|
||||
($lvl:expr, $r:expr) => (
|
||||
FactInstruction::GetList($lvl, $r)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! unify_constant {
|
||||
($c:expr) => (
|
||||
FactInstruction::UnifyConstant($c)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! install_cleaner {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::InstallCleaner)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! check_cp_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CheckCpExecute)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! get_cleaner_call {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::GetCleanerCall)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! restore_cut_policy {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::RestoreCutPolicy)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! ground_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Ground, 1, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! eq_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Eq, 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! not_eq_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::NotEq, 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! compare_term_execute {
|
||||
($qt:expr) => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::CompareTerm($qt), 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_gt {
|
||||
() => (
|
||||
CompareTermQT::GreaterThan
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_lt {
|
||||
() => (
|
||||
CompareTermQT::LessThan
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_gte {
|
||||
() => (
|
||||
CompareTermQT::GreaterThanOrEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_lte {
|
||||
() => (
|
||||
CompareTermQT::LessThanOrEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_ne {
|
||||
() => (
|
||||
CompareTermQT::NotEqual
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! term_cmp_eq {
|
||||
() => (
|
||||
CompareTermQT::Equal
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! install_inference_counter {
|
||||
($r1:expr, $r2:expr, $r3:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::InstallInferenceCounter($r1, $r2, $r3))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! remove_inference_counter {
|
||||
($r1:expr, $r2:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::RemoveInferenceCounter($r1, $r2))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! inference_level {
|
||||
($r1:expr, $r2:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::InferenceLevel($r1, $r2))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! default_set_cp {
|
||||
($r:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::DefaultSetCutPoint($r))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! default_retry_me_else {
|
||||
($o:expr) => (
|
||||
Line::BuiltIn(BuiltInInstruction::DefaultRetryMeElse($o))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! default_trust_me {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::DefaultTrustMe)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! remove_call_policy_check {
|
||||
() => (
|
||||
Line::BuiltIn(BuiltInInstruction::RemoveCallPolicyCheck)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! compare_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Compare, 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! module_decl {
|
||||
($name:expr, $decls:expr) => (
|
||||
ModuleDecl { name: $name, exports: $decls }
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! try_eval_session {
|
||||
($e:expr) => (
|
||||
match $e {
|
||||
@@ -744,41 +203,10 @@ macro_rules! try_eval_session {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! sort_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::Sort, 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! keysort_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::KeySort, 2, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! acyclic_term_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::AcyclicTerm, 1, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! cyclic_term_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::CyclicTerm, 1, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! skip_max_list_execute {
|
||||
() => (
|
||||
Line::Control(ControlInstruction::CallClause(ClauseType::SkipMaxList, 4, 0, true))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! return_from_clause {
|
||||
($lco:expr, $machine_st:expr) => {{
|
||||
if $lco {
|
||||
$machine_st.p = $machine_st.cp.clone();
|
||||
$machine_st.p = CodePtr::Local($machine_st.cp.clone());
|
||||
} else {
|
||||
$machine_st.p += 1;
|
||||
}
|
||||
@@ -787,6 +215,12 @@ macro_rules! return_from_clause {
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! dir_entry {
|
||||
($idx:expr, $module_name:expr) => (
|
||||
CodePtr::Local(LocalCodePtr::DirEntry($idx, $module_name))
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! set_code_index {
|
||||
($idx:expr, $ip:expr, $mod_name:expr) => {{
|
||||
let mut idx = $idx.0.borrow_mut();
|
||||
@@ -801,3 +235,21 @@ macro_rules! machine_code_index {
|
||||
MachineCodeIndex { code_dir: $code_dir, op_dir: $op_dir }
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! put_constant {
|
||||
($lvl:expr, $cons:expr, $r:expr) => (
|
||||
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||
)
|
||||
}
|
||||
|
||||
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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ pub mod ast;
|
||||
#[macro_use]
|
||||
pub mod allocator;
|
||||
pub mod toplevel;
|
||||
pub mod compile;
|
||||
pub mod arithmetic;
|
||||
pub mod builtins;
|
||||
pub mod codegen;
|
||||
pub mod copier;
|
||||
pub mod debray_allocator;
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::vec::Vec;
|
||||
pub struct Frame {
|
||||
pub global_index: usize,
|
||||
pub e: usize,
|
||||
pub cp: CodePtr,
|
||||
pub cp: LocalCodePtr,
|
||||
pub b: usize,
|
||||
pub bp: CodePtr,
|
||||
pub tr: usize,
|
||||
@@ -18,7 +18,7 @@ pub struct Frame {
|
||||
impl Frame {
|
||||
fn new(global_index: usize,
|
||||
e: usize,
|
||||
cp: CodePtr,
|
||||
cp: LocalCodePtr,
|
||||
b: usize,
|
||||
bp: CodePtr,
|
||||
tr: usize,
|
||||
@@ -55,7 +55,7 @@ impl OrStack {
|
||||
pub fn push(&mut self,
|
||||
global_index: usize,
|
||||
e: usize,
|
||||
cp: CodePtr,
|
||||
cp: LocalCodePtr,
|
||||
b: usize,
|
||||
bp: CodePtr,
|
||||
tr: usize,
|
||||
|
||||
Submodule src/prolog/parser updated: 1b3bcc77f2...ae74777868
@@ -1,4 +1,5 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::num::*;
|
||||
use prolog::parser::parser::*;
|
||||
use prolog::tabled_rc::*;
|
||||
@@ -233,7 +234,7 @@ fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term>
|
||||
terms.push(fst);
|
||||
term = snd;
|
||||
}
|
||||
|
||||
|
||||
terms.push(term);
|
||||
terms
|
||||
}
|
||||
@@ -393,34 +394,30 @@ impl RelationWorker {
|
||||
if name.as_str() == "!" || name.as_str() == "blocked_!" {
|
||||
Ok(QueryTerm::BlockedCut)
|
||||
} else {
|
||||
Ok(QueryTerm::Clause(r, ClauseType::Named(name, CodeIndex::default()),
|
||||
vec![]))
|
||||
Ok(QueryTerm::Clause(r, ClauseType::from(name, 0, None), vec![]))
|
||||
},
|
||||
Term::Var(_, ref v) if v.as_str() == "!" =>
|
||||
Ok(QueryTerm::UnblockedCut(Cell::default())),
|
||||
Term::Clause(r, name, mut terms, fixity) =>
|
||||
if let Some(inlined_ct) = InlinedClauseType::from(name.as_str(), terms.len()) {
|
||||
Ok(QueryTerm::Clause(r, ClauseType::Inlined(inlined_ct), terms))
|
||||
} else if name.as_str() == ";" {
|
||||
if terms.len() == 2 {
|
||||
let term = Term::Clause(r, name.clone(), terms, fixity);
|
||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
} else {
|
||||
Err(ParserError::BuiltInArityMismatch(";"))
|
||||
}
|
||||
Term::Clause(r, name, mut terms, fixity) =>
|
||||
if name.as_str() == ";" && terms.len() == 2 {
|
||||
let term = Term::Clause(r, name.clone(), terms, fixity);
|
||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
} else if name.as_str() == "->" && terms.len() == 2 {
|
||||
if terms.len() == 2 {
|
||||
let conq = *terms.pop().unwrap();
|
||||
let prec = *terms.pop().unwrap();
|
||||
let (stub, clauses) = self.fabricate_if_then(prec, conq);
|
||||
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
let conq = *terms.pop().unwrap();
|
||||
let prec = *terms.pop().unwrap();
|
||||
|
||||
let (stub, clauses) = self.fabricate_if_then(prec, conq);
|
||||
|
||||
self.queue.push_back(clauses);
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
} else if name.as_str() == "$get_level" && terms.len() == 1 {
|
||||
if let Term::Var(_, ref var) = *terms[0] {
|
||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
||||
} else {
|
||||
Err(ParserError::BuiltInArityMismatch("->"))
|
||||
Err(ParserError::InadmissibleQueryTerm)
|
||||
}
|
||||
} else {
|
||||
Ok(QueryTerm::Clause(Cell::default(),
|
||||
@@ -568,7 +565,8 @@ impl<R: Read> TopLevelWorker<R> {
|
||||
TopLevelWorker { parser: Parser::new(inner, atom_tbl) }
|
||||
}
|
||||
|
||||
pub fn parse_batch(&mut self, op_dir: &mut OpDir) -> Result<Vec<TopLevelPacket>, SessionError>
|
||||
pub fn parse_batch<'a>(&mut self, wam: &Machine, mut indices: MachineCodeIndex<'a>)
|
||||
-> Result<Vec<TopLevelPacket>, SessionError>
|
||||
{
|
||||
let mut preds = vec![];
|
||||
let mut mod_name = clause_name!("user");
|
||||
@@ -582,7 +580,7 @@ impl<R: Read> TopLevelWorker<R> {
|
||||
|
||||
while !self.parser.eof() {
|
||||
self.parser.reset(); // empty the parser stack of token descriptions.
|
||||
let term = self.parser.read_term(&op_dir)?;
|
||||
let term = self.parser.read_term(&indices.op_dir)?;
|
||||
|
||||
let mut new_rel_worker = RelationWorker::new();
|
||||
let tl = new_rel_worker.try_term_to_tl(term, true)?;
|
||||
@@ -594,8 +592,12 @@ impl<R: Read> TopLevelWorker<R> {
|
||||
rel_worker.absorb(new_rel_worker);
|
||||
|
||||
match tl {
|
||||
TopLevel::Declaration(Declaration::UseModule(name)) =>
|
||||
if let Some(module) = wam.get_module(name) {
|
||||
indices.use_module(module);
|
||||
},
|
||||
TopLevel::Declaration(Declaration::Op(op_decl)) => {
|
||||
op_decl.submit(mod_name.clone(), op_dir)?;
|
||||
op_decl.submit(mod_name.clone(), indices.op_dir)?;
|
||||
},
|
||||
TopLevel::Declaration(Declaration::Module(actual_mod)) => {
|
||||
mod_name = actual_mod.name.clone();
|
||||
@@ -609,7 +611,10 @@ impl<R: Read> TopLevelWorker<R> {
|
||||
};
|
||||
}
|
||||
|
||||
results.push(deque_to_packet(append_preds(&mut preds), rel_worker.parse_queue()?));
|
||||
if !preds.is_empty() {
|
||||
results.push(deque_to_packet(append_preds(&mut preds), rel_worker.parse_queue()?));
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user