From cf9db43d5ba9b542b9f255345e728979ec7a9a2c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 25 Feb 2018 12:13:07 -0700 Subject: [PATCH] major refactor. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/prolog/arithmetic.rs | 32 +- src/prolog/ast.rs | 366 ++++++++++++++--------- src/prolog/builtins.rs | 220 +++++++------- src/prolog/codegen.rs | 250 ++++++++-------- src/prolog/debray_allocator.rs | 13 +- src/prolog/fixtures.rs | 9 +- src/prolog/heap_print.rs | 40 ++- src/prolog/indexing.rs | 5 +- src/prolog/io.rs | 46 ++- src/prolog/iterators.rs | 297 +++++++----------- src/prolog/machine/machine_state.rs | 21 +- src/prolog/machine/machine_state_impl.rs | 121 +++----- src/prolog/machine/mod.rs | 13 +- src/prolog/macros.rs | 48 +-- src/prolog/parser | 2 +- src/prolog/tabled_rc.rs | 26 +- src/prolog/targets.rs | 15 +- src/tests.rs | 4 +- 20 files changed, 727 insertions(+), 805 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27072053..2083ddcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,7 +176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rusty-wam" -version = "0.7.5" +version = "0.7.6" dependencies = [ "downcast 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index b29cd230..bf3be3bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty-wam" -version = "0.7.5" +version = "0.7.6" authors = ["Mark Thom"] [dependencies] diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index e7445828..ce3ce89e 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -13,15 +13,19 @@ pub type ArithCont = (Code, Option); impl<'a> ArithInstructionIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_stack.push(TermIterState::to_state(lvl, term)); + self.state_stack.push(TermIterState::subterm_to_state(lvl, term)); } fn new(term: &'a Term) -> Result { let state = match term { &Term::AnonVar => return Err(ArithmeticError::InvalidTerm), - &Term::Clause(_, ref name, ref terms, _) => - TermIterState::Clause(0, ClauseType::Root(name), terms), + &Term::Clause(ref cell, ref name, ref terms, fixity) => + match ClauseType::from(name.clone(), terms.len(), fixity) { + ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => + Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)), + _ => Err(ArithmeticError::InvalidOp) + }?, &Term::Constant(ref cell, ref cons) => TermIterState::Constant(Level::Shallow, cell, cons), &Term::Cons(_, _, _) => @@ -36,7 +40,7 @@ impl<'a> ArithInstructionIterator<'a> { pub enum ArithTermRef<'a> { Constant(&'a Constant), - Op(&'a str, usize), // name, arity. + Op(ClauseName, usize), // name, arity. Var(&'a Cell, &'a Var) } @@ -48,14 +52,14 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { match iter_state { TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), - TermIterState::Clause(child_num, ct, child_terms) => { - let arity = child_terms.len(); + TermIterState::Clause(lvl, child_num, cell, ct, subterms) => { + let arity = subterms.len(); if child_num == arity { return Some(Ok(ArithTermRef::Op(ct.name(), arity))); } else { - self.state_stack.push(TermIterState::Clause(child_num + 1, ct, child_terms)); - self.push_subterm(ct.level_of_subterms(), child_terms[child_num].as_ref()); + self.state_stack.push(TermIterState::Clause(lvl, child_num + 1, cell, ct, subterms)); + self.push_subterm(lvl, subterms[child_num].as_ref()); } }, TermIterState::Constant(_, _, c) => @@ -97,19 +101,19 @@ impl<'a> ArithmeticEvaluator<'a> ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: target_int } } - fn get_unary_instr(name: &str, a1: ArithmeticTerm, t: usize) + fn get_unary_instr(name: ClauseName, a1: ArithmeticTerm, t: usize) -> Result { - match name { + match name.as_str() { "-" => Ok(ArithmeticInstruction::Neg(a1, t)), _ => Err(ArithmeticError::InvalidOp) } } - fn get_binary_instr(name: &str, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize) + fn get_binary_instr(name: ClauseName, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize) -> Result { - match name { + match name.as_str() { "+" => Ok(ArithmeticInstruction::Add(a1, a2, t)), "-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)), "/" => Ok(ArithmeticInstruction::Div(a1, a2, t)), @@ -137,7 +141,7 @@ impl<'a> ArithmeticEvaluator<'a> temp } - fn instr_from_clause(&mut self, name: &str, arity: usize) + fn instr_from_clause(&mut self, name: ClauseName, arity: usize) -> Result { match arity { @@ -215,7 +219,7 @@ impl<'a> ArithmeticEvaluator<'a> self.interm.push(ArithmeticTerm::Reg(r)); }, ArithTermRef::Op(name, arity) => { - code.push(Line::Arithmetic(self.instr_from_clause(&*name, arity)?)); + code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?)); } } } diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index e89dc89b..ac52c74b 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -8,6 +8,7 @@ use std::cell::Cell; use std::cmp::Ordering; use std::collections::{HashMap, VecDeque}; use std::fmt; +use std::hash::{Hash, Hasher}; use std::io::Error as IOError; use std::num::{ParseFloatError}; use std::ops::{Add, AddAssign, Div, Index, IndexMut, Sub, Mul, Neg}; @@ -46,37 +47,27 @@ impl PredicateClause { pub fn first_arg(&self) -> Option<&Term> { match self { &PredicateClause::Fact(ref term) => term.first_arg(), - &PredicateClause::Rule(ref rule) => - if let &QueryTerm::Term(ref term) = &rule.head.0 { - term.first_arg() - } else { - None - } + &PredicateClause::Rule(ref rule) => rule.head.1.first().map(|bt| bt.as_ref()), } } pub fn arity(&self) -> usize { match self { &PredicateClause::Fact(ref term) => term.arity(), - &PredicateClause::Rule(ref rule) => rule.head.0.arity() + &PredicateClause::Rule(ref rule) => rule.head.1.len() } } - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option { match self { &PredicateClause::Fact(ref term) => term.name(), - &PredicateClause::Rule(ref rule) => - if let &QueryTerm::Term(ref term) = &rule.head.0 { - term.name() - } else { - None - } + &PredicateClause::Rule(ref rule) => Some(rule.head.0.clone()), } } } pub enum Declaration { - Op(usize, Specifier, TabledRc) + Op(usize, Specifier, ClauseName) } pub enum TopLevel { @@ -88,7 +79,7 @@ pub enum TopLevel { } impl TopLevel { - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option { match self { &TopLevel::Declaration(_) => None, &TopLevel::Fact(ref term) => term.name(), @@ -99,15 +90,8 @@ impl TopLevel { None }, &TopLevel::Query(_) => None, - &TopLevel::Rule(Rule { head: (QueryTerm::Term(ref term), _), .. }) => - match term { - &Term::Clause(_, ref name, ..) - | &Term::Constant(_, Constant::Atom(ref name)) => - Some(name.clone()), - _ => - None - }, - _ => None + &TopLevel::Rule(Rule { ref head, .. }) => + Some(head.0.clone()) } } @@ -118,14 +102,23 @@ impl TopLevel { &TopLevel::Predicate(ref clauses) => clauses.first().map(|t| t.arity()).unwrap_or(0), &TopLevel::Query(_) => 0, - &TopLevel::Rule(Rule { head: (ref qt, _), ..}) => qt.arity(), + &TopLevel::Rule(Rule { ref head, .. }) => head.1.len() } } } #[derive(Clone, Copy)] pub enum Level { - Deep, Shallow + Deep, Root, Shallow +} + +impl Level { + pub fn child_level(self) -> Level { + match self { + Level::Root => Level::Shallow, + _ => Level::Deep + } + } } #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -305,7 +298,7 @@ pub enum Fixity { #[derive(Clone, Eq, Hash, PartialEq)] pub enum Constant { - Atom(TabledRc), + Atom(ClauseName), Number(Number), String(Rc), Usize(usize), @@ -332,36 +325,57 @@ impl fmt::Display for Constant { #[derive(PartialEq, Eq, Clone)] pub enum Term { AnonVar, - Clause(Cell, TabledRc, Vec>, Option), + Clause(Cell, ClauseName, Vec>, Option), Cons(Cell, Box, Box), Constant(Cell, Constant), Var(Cell, Rc) } -pub enum InlinedQueryTerm { - CompareNumber(CompareNumberQT, Vec>), - IsAtomic(Vec>), - IsCompound(Vec>), - IsInteger(Vec>), - IsRational(Vec>), - IsString(Vec>), - IsFloat(Vec>), - IsNonVar(Vec>), - IsVar(Vec>), -} - -impl InlinedQueryTerm { - pub fn arity(&self) -> usize { +#[derive(Clone, Copy)] +pub enum InlinedClauseType { + CompareNumber(CompareNumberQT), + IsAtomic, + IsCompound, + IsInteger, + IsRational, + IsString, + IsFloat, + IsNonVar, + IsVar, +} + +impl InlinedClauseType { + pub fn name(&self) -> &'static str { match self { - &InlinedQueryTerm::CompareNumber(_, _) => 2, - &InlinedQueryTerm::IsAtomic(_) => 1, - &InlinedQueryTerm::IsCompound(_) => 1, - &InlinedQueryTerm::IsFloat(_) => 1, - &InlinedQueryTerm::IsRational(_) => 1, - &InlinedQueryTerm::IsString(_) => 1, - &InlinedQueryTerm::IsNonVar(_) => 1, - &InlinedQueryTerm::IsInteger(_) => 1, - &InlinedQueryTerm::IsVar(_) => 1, + &InlinedClauseType::CompareNumber(qt) => qt.name(), + &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 { + 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)), + ("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), + _ => None } } } @@ -377,7 +391,7 @@ pub enum CompareNumberQT { } impl CompareNumberQT { - fn name<'a>(self) -> &'a str { + fn name(self) -> &'static str { match self { CompareNumberQT::GreaterThan => ">", CompareNumberQT::LessThan => "<", @@ -390,13 +404,13 @@ impl CompareNumberQT { } #[derive(Clone, Copy)] -pub enum CompareTermQT { +pub enum CompareTermQT { LessThan, LessThanOrEqual, Equal, GreaterThanOrEqual, - GreaterThan, - NotEqual, + GreaterThan, + NotEqual, } impl CompareTermQT { @@ -417,118 +431,174 @@ impl CompareTermQT { pub type JumpStub = Vec; pub enum QueryTerm { - Arg(Vec>), - CallN(Vec>), - CallWithInferenceLimit(Vec>), - Catch(Vec>), - Compare(Vec>), - CompareTerm(CompareTermQT, Vec>), + Clause(Cell, ClauseType, Vec>), Cut, - Display(Vec>), - DuplicateTerm(Vec>), - Eq(Vec>), - Functor(Vec>), - Ground(Vec>), - Inlined(InlinedQueryTerm), - Is(Vec>), - Jump(JumpStub), - NotEq(Vec>), - SetupCallCleanup(Vec>), - Term(Term), - Throw(Vec>) + Jump(JumpStub) } impl QueryTerm { pub fn arity(&self) -> usize { match self { - &QueryTerm::Arg(_) => 3, - &QueryTerm::Catch(_) => 3, - &QueryTerm::Compare(_) => 3, - &QueryTerm::CompareTerm(..) => 2, - &QueryTerm::Display(_) => 1, - &QueryTerm::Throw(_) => 1, - &QueryTerm::DuplicateTerm(_) => 2, - &QueryTerm::Eq(_) => 2, - &QueryTerm::Functor(_) => 3, - &QueryTerm::Ground(_) => 1, - &QueryTerm::Inlined(ref term) => term.arity(), - &QueryTerm::Is(_) => 2, - &QueryTerm::Jump(ref vars) => vars.len(), - &QueryTerm::NotEq(_) => 2, - &QueryTerm::CallN(ref terms) => terms.len(), - &QueryTerm::CallWithInferenceLimit(_) => 3, + &QueryTerm::Clause(_, _, ref subterms) => subterms.len(), &QueryTerm::Cut => 0, - &QueryTerm::SetupCallCleanup(_) => 3, - &QueryTerm::Term(ref term) => term.arity(), + &QueryTerm::Jump(ref vars) => vars.len() } } } pub struct Rule { - pub head: (QueryTerm, QueryTerm), + pub head: (ClauseName, Vec>, QueryTerm), pub clauses: Vec } -#[derive(Clone, Copy)] -pub enum ClauseType<'a> { +#[derive(Clone)] +pub enum ClauseType { Arg, CallN, CallWithInferenceLimit, Catch, Compare, - CompareNumber(CompareNumberQT), CompareTerm(CompareTermQT), - Deep(Level, &'a Cell, &'a TabledRc, Option), Display, DuplicateTerm, Eq, Functor, Ground, + Inlined(InlinedClauseType), Is, NotEq, - Root(&'a TabledRc), + Op(ClauseName, Fixity), + Named(ClauseName), SetupCallCleanup, Throw, } -impl<'a> ClauseType<'a> { - pub fn name(&self) -> &'a str { +impl ClauseType { + pub fn fixity(&self) -> Option { + match self { + &ClauseType::Compare | &ClauseType::CompareTerm(_) + | &ClauseType::Inlined(InlinedClauseType::CompareNumber(_)) + | &ClauseType::NotEq | &ClauseType::Is | &ClauseType::Eq => Some(Fixity::In), + &ClauseType::Op(_, fixity) => Some(fixity), + _ => None + } + } +} + +#[derive(Clone)] +pub enum ClauseName { + BuiltIn(&'static str), + User(TabledRc) +} + +impl Hash for ClauseName { + fn hash(&self, state: &mut H) { + (*self.as_str()).hash(state) + } +} + +impl PartialEq for ClauseName { + fn eq(&self, other: &ClauseName) -> bool { + *self.as_str() == *other.as_str() + } +} + +impl Eq for ClauseName {} + +impl Ord for ClauseName { + fn cmp(&self, other: &ClauseName) -> Ordering { + (*self.as_str()).cmp(other.as_str()) + } +} + +impl PartialOrd for ClauseName { + fn partial_cmp(&self, other: &ClauseName) -> Option { + Some(self.cmp(other)) + } +} + +impl<'a> From<&'a TabledRc> for ClauseName { + fn from(name: &'a TabledRc) -> ClauseName { + ClauseName::User(name.clone()) + } +} + +impl ClauseName { + pub fn as_str(&self) -> &str { match self { - &ClauseType::Arg => "arg", - &ClauseType::CallN => "call", - &ClauseType::CallWithInferenceLimit => "call_with_inference_limit", - &ClauseType::Catch => "catch", - &ClauseType::Compare => "compare", - &ClauseType::CompareNumber(qt) => qt.name(), - &ClauseType::CompareTerm(qt) => qt.name(), - &ClauseType::Display => "display", - &ClauseType::Deep(_, _, name, _) => name.as_str(), - &ClauseType::DuplicateTerm => "duplicate_term", - &ClauseType::Eq => "==", - &ClauseType::Functor => "functor", - &ClauseType::Ground => "ground", - &ClauseType::Is => "is", - &ClauseType::NotEq => "\\==", - &ClauseType::Root(name) => name.as_str(), - &ClauseType::SetupCallCleanup => "setup_call_cleanup", - &ClauseType::Throw => "throw" + &ClauseName::BuiltIn(s) => s, + &ClauseName::User(ref name) => name.as_ref() } } +} - pub fn level_of_subterms(self) -> Level { +impl ClauseType { + pub fn name(&self) -> ClauseName { match self { - ClauseType::Deep(..) => Level::Deep, - _ => Level::Shallow + &ClauseType::Arg => ClauseName::BuiltIn("arg"), + &ClauseType::CallN => ClauseName::BuiltIn("call"), + &ClauseType::CallWithInferenceLimit => ClauseName::BuiltIn("call_with_inference_limit"), + &ClauseType::Catch => ClauseName::BuiltIn("catch"), + &ClauseType::Compare => ClauseName::BuiltIn("compare"), + &ClauseType::CompareTerm(qt) => ClauseName::BuiltIn(qt.name()), + &ClauseType::Display => ClauseName::BuiltIn("display"), + &ClauseType::DuplicateTerm => ClauseName::BuiltIn("duplicate_term"), + &ClauseType::Eq => ClauseName::BuiltIn("=="), + &ClauseType::Functor => ClauseName::BuiltIn("functor"), + &ClauseType::Ground => ClauseName::BuiltIn("ground"), + &ClauseType::Inlined(inlined) => ClauseName::BuiltIn(inlined.name()), + &ClauseType::Is => ClauseName::BuiltIn("is"), + &ClauseType::NotEq => ClauseName::BuiltIn("\\=="), + &ClauseType::Op(ref name, _) => name.clone(), + &ClauseType::Named(ref name) => name.clone(), + &ClauseType::SetupCallCleanup => ClauseName::BuiltIn("setup_call_cleanup"), + &ClauseType::Throw => ClauseName::BuiltIn("throw") + } + } + + pub fn from(name: ClauseName, arity: usize, fixity: Option) -> Self { + match (name.as_str(), arity) { + ("arg", 3) => ClauseType::Arg, + ("call", _) => ClauseType::CallN, + ("call_with_inference_limit", 3) => ClauseType::CallWithInferenceLimit, + ("catch", 3) => ClauseType::Catch, + ("compare", 3) => ClauseType::Compare, + ("@>", 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, + ("\\==", 2) => ClauseType::NotEq, + ("setup_call_cleanup", 3) => ClauseType::SetupCallCleanup, + ("throw", 1) => ClauseType::Throw, + _ => if let Some(fixity) = fixity { + ClauseType::Op(name, fixity) + } else { + ClauseType::Named(name) + } } } } -#[derive(Clone, Copy)] +impl From for ClauseType { + fn from(inlined_ct: InlinedClauseType) -> Self { + ClauseType::Inlined(inlined_ct) + } +} + +#[derive(Clone)] pub enum TermRef<'a> { AnonVar(Level), Cons(Level, &'a Cell, &'a Term, &'a Term), Constant(Level, &'a Cell, &'a Constant), - Clause(ClauseType<'a>, &'a Vec>), + Clause(Level, &'a Cell, ClauseType, &'a Vec>), Var(Level, &'a Cell, &'a Var) } @@ -538,9 +608,8 @@ impl<'a> TermRef<'a> { TermRef::AnonVar(lvl) | TermRef::Cons(lvl, ..) | TermRef::Constant(lvl, ..) - | TermRef::Var(lvl, ..) => lvl, - TermRef::Clause(ClauseType::Deep(lvl, ..), ..) => lvl, - _ => Level::Shallow + | TermRef::Var(lvl, ..) + | TermRef::Clause(lvl, ..) => lvl } } } @@ -921,7 +990,7 @@ pub enum ControlInstruction { Allocate(usize), // num_frames. ArgCall, ArgExecute, - Call(TabledRc, usize, usize), // name, arity, perm_vars after threshold. + Call(ClauseName, usize, usize), // name, arity, perm_vars after threshold. CallN(usize), // arity. CatchCall, CatchExecute, @@ -934,11 +1003,11 @@ pub enum ControlInstruction { DisplayExecute, Deallocate, DuplicateTermCall, - DuplicateTermExecute, + DuplicateTermExecute, DynamicIs, EqCall, EqExecute, - Execute(TabledRc, usize), + Execute(ClauseName, usize), ExecuteN(usize), FunctorCall, FunctorExecute, @@ -949,11 +1018,11 @@ pub enum ControlInstruction { GroundExecute, JmpByCall(usize, usize), // arity, global_offset. JmpByExecute(usize, usize), - IsCall(RegType, ArithmeticTerm), + IsCall(RegType, ArithmeticTerm), IsExecute(RegType, ArithmeticTerm), NotEqCall, NotEqExecute, - Proceed, + Proceed, ThrowCall, ThrowExecute, } @@ -965,7 +1034,7 @@ impl ControlInstruction { &ControlInstruction::ArgExecute => true, &ControlInstruction::Call(_, _, _) => true, &ControlInstruction::CatchCall => true, - &ControlInstruction::CatchExecute => true, + &ControlInstruction::CatchExecute => true, &ControlInstruction::CompareTermCall(..) => true, &ControlInstruction::CompareTermExecute(..) => true, &ControlInstruction::DisplayCall => true, @@ -1003,7 +1072,7 @@ impl ControlInstruction { pub enum IndexingInstruction { SwitchOnTerm(usize, usize, usize, usize), SwitchOnConstant(usize, HashMap), - SwitchOnStructure(usize, HashMap<(TabledRc, usize), usize>) + SwitchOnStructure(usize, HashMap<(ClauseName, usize), usize>) } impl From for Line { @@ -1015,7 +1084,7 @@ impl From for Line { pub enum FactInstruction { GetConstant(Level, Constant, RegType), GetList(Level, RegType), - GetStructure(Level, TabledRc, usize, RegType, Option), + GetStructure(ClauseType, usize, RegType), GetValue(RegType, usize), GetVariable(RegType, usize), UnifyConstant(Constant), @@ -1029,7 +1098,7 @@ pub enum QueryInstruction { GetVariable(RegType, usize), PutConstant(Level, Constant, RegType), PutList(Level, RegType), - PutStructure(Level, TabledRc, usize, RegType, Option), + PutStructure(ClauseType, usize, RegType), PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), @@ -1113,7 +1182,7 @@ pub enum Ref { #[derive(Clone, PartialEq)] pub enum HeapCellValue { Addr(Addr), - NamedStr(usize, TabledRc, Option), // arity, name, fixity if it has one. + NamedStr(usize, ClauseName, Option), // arity, name, fixity if it has one. } impl HeapCellValue { @@ -1233,15 +1302,7 @@ impl Term { } } - pub fn is_callable(&self) -> bool { - match self { - &Term::Clause(..) | &Term::Constant(_, Constant::Atom(_)) => - true, - _ => false - } - } - - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option { match self { &Term::Constant(_, Constant::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => Some(atom.clone()), @@ -1259,20 +1320,27 @@ impl Term { pub enum TermIterState<'a> { AnonVar(Level), - Clause(usize, ClauseType<'a>, &'a Vec>), Constant(Level, &'a Cell, &'a Constant), + Clause(Level, usize, &'a Cell, ClauseType, &'a Vec>), InitialCons(Level, &'a Cell, &'a Term, &'a Term), FinalCons(Level, &'a Cell, &'a Term, &'a Term), Var(Level, &'a Cell, &'a Var) } impl<'a> TermIterState<'a> { - pub fn to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { + pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { match term { &Term::AnonVar => TermIterState::AnonVar(lvl), - &Term::Clause(ref cell, ref atom, ref child_terms, fixity) => - TermIterState::Clause(0, ClauseType::Deep(lvl, cell, atom, fixity), child_terms), + &Term::Clause(ref cell, ref name, ref subterms, fixity) => { + let ct = if let Some(fixity) = fixity { + ClauseType::Op(name.clone(), fixity) + } else { + ClauseType::Named(name.clone()) + }; + + TermIterState::Clause(lvl, 0, cell, ct, subterms) + }, &Term::Cons(ref cell, ref head, ref tail) => TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()), &Term::Constant(ref cell, ref constant) => diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 41606caa..649fc3ae 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -1,11 +1,10 @@ use prolog::ast::*; use prolog::num::bigint::{BigInt}; -use prolog::tabled_rc::*; use std::collections::HashMap; use std::rc::Rc; -pub type PredicateKey = (TabledRc, usize); // name, arity, type. +pub type PredicateKey = (ClauseName, usize); // name, arity, type. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum PredicateKeyType { @@ -13,13 +12,13 @@ pub enum PredicateKeyType { User } -pub type OpDirKey = (TabledRc, Fixity); +pub type OpDirKey = (ClauseName, Fixity); // name and fixity -> operator type and precedence. pub type OpDir = HashMap; pub type CodeDir = HashMap; -fn get_builtins(atom_tbl: TabledData) -> Code { +fn get_builtins() -> Code { vec![internal_call_n!(), // callN/N, 0. is_atomic!(temp_v!(1)), // atomic/1, 1. proceed!(), @@ -115,25 +114,25 @@ fn get_builtins(atom_tbl: TabledData) -> Code { retry!(7), trust!(10), try_me_else!(4), - fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)), - get_structure!(atom_tbl, ",", 2, temp_v!(2), Some(infix!())), + 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!(83, 3), retry_me_else!(4), - fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)), - get_constant!(atom!("!", atom_tbl), temp_v!(2))], + 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!("!", atom_tbl), temp_v!(1))], + 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), allocate!(3), - fact![get_structure!(atom_tbl, ",", 2, temp_v!(2), Some(infix!())), + 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)], @@ -147,7 +146,7 @@ fn get_builtins(atom_tbl: TabledData) -> Code { retry_me_else!(10), allocate!(2), get_level!(perm_v!(2)), - fact![get_constant!(atom!("!", atom_tbl), temp_v!(2)), + fact![get_constant!(atom!("!"), temp_v!(2)), get_var_in_fact!(perm_v!(1), 3)], neck_cut!(), call_n!(1), @@ -168,12 +167,12 @@ fn get_builtins(atom_tbl: TabledData) -> Code { indexed_try!(3), trust!(5), try_me_else!(3), - fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), + fact![get_structure!("->", 2, temp_v!(1), Some(infix!())), unify_variable!(temp_v!(1)), unify_variable!(temp_v!(2))], goto_execute!(139, 3), trust_me!(), - fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), + fact![get_structure!("->", 2, temp_v!(1), Some(infix!())), unify_void!(2)], query![put_value!(temp_v!(2), 1)], neck_cut!(), @@ -232,13 +231,8 @@ fn get_builtins(atom_tbl: TabledData) -> Code { goto_execute!(149, 3), // goto get_arg/3. trust_me!(), query![get_var_in_query!(temp_v!(4), 1), - put_structure!(atom_tbl, - Level::Shallow, - String::from("type_error"), - 1, - temp_v!(1), - None), - set_constant!(atom!("integer_expected", atom_tbl))], + put_structure!("type_error", 1, temp_v!(1), None), + set_constant!(atom!("integer_expected"))], goto_execute!(59, 1), // goto throw/1. try_me_else!(5), // arg_/5, 173. fact![get_value!(temp_v!(1), 2), @@ -405,13 +399,8 @@ fn get_builtins(atom_tbl: TabledData) -> Code { trust_me!(), fact![get_var_in_fact!(temp_v!(3), 1), get_var_in_fact!(temp_v!(4), 2)], - query![put_structure!(atom_tbl, - Level::Shallow, - String::from("type_error"), - 2, - temp_v!(1), - None), - set_constant!(atom!("integer_expected", atom_tbl)), + 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, 59. switch_on_term!(1,2,5,0), // length/3, 281. @@ -453,7 +442,8 @@ fn get_builtins(atom_tbl: TabledData) -> Code { try_me_else!(5), // 304. is_var!(temp_v!(1)), neck_cut!(), - query![put_constant!(Level::Shallow, atom!("instantiation_error", atom_tbl), + query![put_constant!(Level::Shallow, + atom!("instantiation_error"), temp_v!(1))], goto_execute!(59, 1), trust_me!(), @@ -502,7 +492,7 @@ fn get_builtins(atom_tbl: TabledData) -> Code { get_cleaner_call!(), query![put_value!(perm_v!(2), 1), put_var!(temp_v!(4), 2), - put_constant!(Level::Shallow, atom!("true", atom_tbl), temp_v!(3))], + put_constant!(Level::Shallow, atom!("true"), temp_v!(3))], goto_call!(5, 3), // goto catch/3, 5. set_cp!(perm_v!(1)), deallocate!(), @@ -621,9 +611,9 @@ fn get_builtins(atom_tbl: TabledData) -> Code { remove_call_policy_check!(), fail!(), try_me_else!(4), // handle_ile/3, 444. - fact![get_structure!(atom_tbl, "inference_limit_exceeded", 1, temp_v!(2), None), + fact![get_structure!("inference_limit_exceeded", 1, temp_v!(2), None), unify_value!(temp_v!(1)), - get_constant!(atom!("inference_limit_exceeded", atom_tbl), temp_v!(3))], + get_constant!(atom!("inference_limit_exceeded"), temp_v!(3))], neck_cut!(), proceed!(), default_trust_me!(), @@ -648,119 +638,119 @@ fn get_builtins(atom_tbl: TabledData) -> Code { ] } -pub fn build_code_dir(atom_tbl: TabledData) -> (Code, CodeDir, OpDir) +pub fn build_code_dir() -> (Code, CodeDir, OpDir) { let mut code_dir = HashMap::new(); let mut op_dir = HashMap::new(); - let builtin_code = get_builtins(atom_tbl.clone()); + let builtin_code = get_builtins(); - op_dir.insert((tabled_rc!(":-", atom_tbl), Fixity::In), (XFX, 1200)); - op_dir.insert((tabled_rc!(":-", atom_tbl), Fixity::Pre), (FX, 1200)); - op_dir.insert((tabled_rc!("?-", atom_tbl), Fixity::Pre), (FX, 1200)); + op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200)); + op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200)); + op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200)); // control operators. - op_dir.insert((tabled_rc!("\\+", atom_tbl), Fixity::Pre), (FY, 900)); - op_dir.insert((tabled_rc!("=", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("\\+"), Fixity::Pre), (FY, 900)); + op_dir.insert((clause_name!("="), Fixity::In), (XFX, 700)); // arithmetic operators. - op_dir.insert((tabled_rc!("is", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("+", atom_tbl), Fixity::In), (YFX, 500)); - op_dir.insert((tabled_rc!("-", atom_tbl), Fixity::In), (YFX, 500)); - op_dir.insert((tabled_rc!("/\\", atom_tbl), Fixity::In), (YFX, 500)); - op_dir.insert((tabled_rc!("\\/", atom_tbl), Fixity::In), (YFX, 500)); - op_dir.insert((tabled_rc!("xor", atom_tbl), Fixity::In), (YFX, 500)); - op_dir.insert((tabled_rc!("//", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("/", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("div", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("*", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("-", atom_tbl), Fixity::Pre), (FY, 200)); - op_dir.insert((tabled_rc!("rdiv", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("<<", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!(">>", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("mod", atom_tbl), Fixity::In), (YFX, 400)); - op_dir.insert((tabled_rc!("rem", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("is"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("+"), Fixity::In), (YFX, 500)); + op_dir.insert((clause_name!("-"), Fixity::In), (YFX, 500)); + op_dir.insert((clause_name!("/\\"), Fixity::In), (YFX, 500)); + op_dir.insert((clause_name!("\\/"), Fixity::In), (YFX, 500)); + op_dir.insert((clause_name!("xor"), Fixity::In), (YFX, 500)); + op_dir.insert((clause_name!("//"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("/"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("div"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("*"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("-"), Fixity::Pre), (FY, 200)); + op_dir.insert((clause_name!("rdiv"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("<<"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!(">>"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("mod"), Fixity::In), (YFX, 400)); + op_dir.insert((clause_name!("rem"), Fixity::In), (YFX, 400)); // arithmetic comparison operators. - op_dir.insert((tabled_rc!(">", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("<", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("=\\=", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("=:=", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!(">=", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("=<", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!(">"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("<"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=\\="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=:="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!(">="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=<"), Fixity::In), (XFX, 700)); // control operators. - op_dir.insert((tabled_rc!(";", atom_tbl), Fixity::In), (XFY, 1100)); - op_dir.insert((tabled_rc!("->", atom_tbl), Fixity::In), (XFY, 1050)); + op_dir.insert((clause_name!(";"), Fixity::In), (XFY, 1100)); + op_dir.insert((clause_name!("->"), Fixity::In), (XFY, 1050)); - op_dir.insert((tabled_rc!("=..", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("==", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("\\==", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("@=<", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("@>=", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("@<", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("@>", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("=@=", atom_tbl), Fixity::In), (XFX, 700)); - op_dir.insert((tabled_rc!("\\=@=", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=.."), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("\\=="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("@=<"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("@>="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("@<"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("@>"), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700)); + op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700)); // 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((tabled_rc!("call", atom_tbl), arity), (PredicateKeyType::BuiltIn, 0)); + code_dir.insert((clause_name!("call"), arity), (PredicateKeyType::BuiltIn, 0)); } - code_dir.insert((tabled_rc!("atomic", atom_tbl), 1), (PredicateKeyType::BuiltIn, 1)); - code_dir.insert((tabled_rc!("var", atom_tbl), 1), (PredicateKeyType::BuiltIn, 3)); - code_dir.insert((tabled_rc!("false", atom_tbl), 0), (PredicateKeyType::BuiltIn, 61)); - code_dir.insert((tabled_rc!("\\+", atom_tbl), 1), (PredicateKeyType::BuiltIn, 62)); - code_dir.insert((tabled_rc!("duplicate_term", atom_tbl), 2), (PredicateKeyType::BuiltIn, 71)); - code_dir.insert((tabled_rc!("catch", atom_tbl), 3), (PredicateKeyType::BuiltIn, 5)); - code_dir.insert((tabled_rc!("throw", atom_tbl), 1), (PredicateKeyType::BuiltIn, 59)); - code_dir.insert((tabled_rc!("=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 73)); - code_dir.insert((tabled_rc!("true", atom_tbl), 0), (PredicateKeyType::BuiltIn, 75)); + code_dir.insert((clause_name!("atomic"), 1), (PredicateKeyType::BuiltIn, 1)); + code_dir.insert((clause_name!("var"), 1), (PredicateKeyType::BuiltIn, 3)); + code_dir.insert((clause_name!("false"), 0), (PredicateKeyType::BuiltIn, 61)); + code_dir.insert((clause_name!("\\+"), 1), (PredicateKeyType::BuiltIn, 62)); + code_dir.insert((clause_name!("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71)); + code_dir.insert((clause_name!("catch"), 3), (PredicateKeyType::BuiltIn, 5)); + code_dir.insert((clause_name!("throw"), 1), (PredicateKeyType::BuiltIn, 59)); + code_dir.insert((clause_name!("="), 2), (PredicateKeyType::BuiltIn, 73)); + code_dir.insert((clause_name!("true"), 0), (PredicateKeyType::BuiltIn, 75)); - code_dir.insert((tabled_rc!(",", atom_tbl), 2), (PredicateKeyType::BuiltIn, 76)); - code_dir.insert((tabled_rc!(";", atom_tbl), 2), (PredicateKeyType::BuiltIn, 120)); - code_dir.insert((tabled_rc!("->", atom_tbl), 2), (PredicateKeyType::BuiltIn, 138)); + code_dir.insert((clause_name!(","), 2), (PredicateKeyType::BuiltIn, 76)); + code_dir.insert((clause_name!(";"), 2), (PredicateKeyType::BuiltIn, 120)); + code_dir.insert((clause_name!("->"), 2), (PredicateKeyType::BuiltIn, 138)); - code_dir.insert((tabled_rc!("functor", atom_tbl), 3), (PredicateKeyType::BuiltIn, 146)); - code_dir.insert((tabled_rc!("arg", atom_tbl), 3), (PredicateKeyType::BuiltIn, 150)); - code_dir.insert((tabled_rc!("integer", atom_tbl), 1), (PredicateKeyType::BuiltIn, 147)); - code_dir.insert((tabled_rc!("display", atom_tbl), 1), (PredicateKeyType::BuiltIn, 192)); + code_dir.insert((clause_name!("functor"), 3), (PredicateKeyType::BuiltIn, 146)); + code_dir.insert((clause_name!("arg"), 3), (PredicateKeyType::BuiltIn, 150)); + code_dir.insert((clause_name!("integer"), 1), (PredicateKeyType::BuiltIn, 147)); + code_dir.insert((clause_name!("display"), 1), (PredicateKeyType::BuiltIn, 192)); - code_dir.insert((tabled_rc!("is", atom_tbl), 2), (PredicateKeyType::BuiltIn, 194)); - code_dir.insert((tabled_rc!(">", atom_tbl), 2), (PredicateKeyType::BuiltIn, 196)); - code_dir.insert((tabled_rc!("<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 198)); - code_dir.insert((tabled_rc!(">=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 200)); - code_dir.insert((tabled_rc!("<=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 202)); - code_dir.insert((tabled_rc!("=\\=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 204)); - code_dir.insert((tabled_rc!("=:=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 206)); - code_dir.insert((tabled_rc!("=..", atom_tbl), 2), (PredicateKeyType::BuiltIn, 208)); + code_dir.insert((clause_name!("is"), 2), (PredicateKeyType::BuiltIn, 194)); + code_dir.insert((clause_name!(">"), 2), (PredicateKeyType::BuiltIn, 196)); + code_dir.insert((clause_name!("<"), 2), (PredicateKeyType::BuiltIn, 198)); + code_dir.insert((clause_name!(">="), 2), (PredicateKeyType::BuiltIn, 200)); + code_dir.insert((clause_name!("<="), 2), (PredicateKeyType::BuiltIn, 202)); + code_dir.insert((clause_name!("=\\="), 2), (PredicateKeyType::BuiltIn, 204)); + code_dir.insert((clause_name!("=:="), 2), (PredicateKeyType::BuiltIn, 206)); + code_dir.insert((clause_name!("=.."), 2), (PredicateKeyType::BuiltIn, 208)); - code_dir.insert((tabled_rc!("length", atom_tbl), 2), (PredicateKeyType::BuiltIn, 261)); - code_dir.insert((tabled_rc!("setup_call_cleanup", atom_tbl), 3), + code_dir.insert((clause_name!("length"), 2), (PredicateKeyType::BuiltIn, 261)); + code_dir.insert((clause_name!("setup_call_cleanup"), 3), (PredicateKeyType::BuiltIn, 294)); - code_dir.insert((tabled_rc!("call_with_inference_limit", atom_tbl), 3), + code_dir.insert((clause_name!("call_with_inference_limit"), 3), (PredicateKeyType::BuiltIn, 393)); - code_dir.insert((tabled_rc!("_handle_inference_limit_exceeded", atom_tbl), 2), + code_dir.insert((clause_name!("_handle_inference_limit_exceeded"), 2), (PredicateKeyType::BuiltIn, 421)); - code_dir.insert((tabled_rc!("compound", atom_tbl), 1), (PredicateKeyType::BuiltIn, 372)); - code_dir.insert((tabled_rc!("rational", atom_tbl), 1), (PredicateKeyType::BuiltIn, 374)); - code_dir.insert((tabled_rc!("string", atom_tbl), 1), (PredicateKeyType::BuiltIn, 376)); - code_dir.insert((tabled_rc!("float", atom_tbl), 1), (PredicateKeyType::BuiltIn, 378)); - code_dir.insert((tabled_rc!("nonvar", atom_tbl), 1), (PredicateKeyType::BuiltIn, 380)); + code_dir.insert((clause_name!("compound"), 1), (PredicateKeyType::BuiltIn, 372)); + code_dir.insert((clause_name!("rational"), 1), (PredicateKeyType::BuiltIn, 374)); + code_dir.insert((clause_name!("string"), 1), (PredicateKeyType::BuiltIn, 376)); + code_dir.insert((clause_name!("float"), 1), (PredicateKeyType::BuiltIn, 378)); + code_dir.insert((clause_name!("nonvar"), 1), (PredicateKeyType::BuiltIn, 380)); - code_dir.insert((tabled_rc!("ground", atom_tbl), 1), (PredicateKeyType::BuiltIn, 384)); - code_dir.insert((tabled_rc!("==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 385)); - code_dir.insert((tabled_rc!("\\==", atom_tbl), 2), (PredicateKeyType::BuiltIn, 386)); - code_dir.insert((tabled_rc!("@>=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 387)); - code_dir.insert((tabled_rc!("@=<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 388)); - code_dir.insert((tabled_rc!("@>", atom_tbl), 2), (PredicateKeyType::BuiltIn, 389)); - code_dir.insert((tabled_rc!("@<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 390)); - code_dir.insert((tabled_rc!("=@=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 391)); - code_dir.insert((tabled_rc!("\\=@=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 392)); - code_dir.insert((tabled_rc!("compare", atom_tbl), 3), (PredicateKeyType::BuiltIn, 464)); + code_dir.insert((clause_name!("ground"), 1), (PredicateKeyType::BuiltIn, 384)); + code_dir.insert((clause_name!("=="), 2), (PredicateKeyType::BuiltIn, 385)); + code_dir.insert((clause_name!("\\=="), 2), (PredicateKeyType::BuiltIn, 386)); + code_dir.insert((clause_name!("@>="), 2), (PredicateKeyType::BuiltIn, 387)); + code_dir.insert((clause_name!("@=<"), 2), (PredicateKeyType::BuiltIn, 388)); + code_dir.insert((clause_name!("@>"), 2), (PredicateKeyType::BuiltIn, 389)); + code_dir.insert((clause_name!("@<"), 2), (PredicateKeyType::BuiltIn, 390)); + code_dir.insert((clause_name!("=@="), 2), (PredicateKeyType::BuiltIn, 391)); + code_dir.insert((clause_name!("\\=@="), 2), (PredicateKeyType::BuiltIn, 392)); + code_dir.insert((clause_name!("compare"), 3), (PredicateKeyType::BuiltIn, 464)); (builtin_code, code_dir, op_dir) } diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 9d3b61c0..0c12c03a 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -156,25 +156,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> }; } - fn compile_clause(&mut self, ct: ClauseType<'a>, term_loc: GenContext, - is_exposed: bool, terms: &'a Vec>, - target: &mut Vec) - where Target: CompilationTarget<'a> - { - match ct { - ClauseType::Deep(lvl, cell, atom, fixity) => { - self.marker.mark_non_var(lvl, term_loc, cell, target); - target.push(Target::to_structure(lvl, atom.clone(), terms.len(), - cell.get(), fixity)); - - for subterm in terms { - self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, target); - } - }, - _ => {} - } - } - fn compile_target(&mut self, iter: Iter, term_loc: GenContext, is_exposed: bool) -> Vec where Target: CompilationTarget<'a>, Iter: Iterator> @@ -183,8 +164,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> for term in iter { match term { - TermRef::Clause(ct, terms) => - self.compile_clause(ct, term_loc, is_exposed, terms, &mut target), + TermRef::Clause(lvl, cell, ct, terms) => { + self.marker.mark_non_var(lvl, term_loc, cell, &mut target); + target.push(Target::to_structure(ct, terms.len(), cell.get())); + + for subterm in terms { + self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target); + } + }, TermRef::Cons(lvl, cell, head, tail) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); target.push(Target::to_list(lvl, cell.get())); @@ -214,24 +201,24 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> { let mut vs = VariableFixtures::new(); - let at_rule_head = iter.at_rule_head(); - while let Some((chunk_num, lt_arity, terms)) = iter.next() { - for (i, query_term) in terms.iter().enumerate() { - let term_loc = if chunk_num == 0 && i == 0 && at_rule_head { - GenContext::Head - } else if i < terms.len() - 1 { - GenContext::Mid(chunk_num) - } else { - GenContext::Last(chunk_num) - }; + while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() { + for (i, chunked_term) in chunked_terms.iter().enumerate() { + let term_loc = match chunked_term { + &ChunkedTerm::HeadClause(..) => GenContext::Head, + &ChunkedTerm::BodyTerm(_) => if i < chunked_terms.len() - 1 { + GenContext::Mid(chunk_num) + } else { + GenContext::Last(chunk_num) + } + }; - self.update_var_count(query_term.post_order_iter()); - vs.mark_vars_in_chunk(query_term.post_order_iter(), lt_arity, term_loc); + self.update_var_count(chunked_term.post_order_iter()); + vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc); } } - let num_of_chunks = iter.chunk_num(); + let num_of_chunks = iter.chunk_num; let has_deep_cut = iter.encountered_deep_cut(); vs.populate_restricting_sets(); @@ -245,51 +232,51 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) { match qt { - &QueryTerm::CallWithInferenceLimit(_) => - code.push(goto_call!(393, 3)), - &QueryTerm::SetupCallCleanup(_) => - code.push(goto_call!(294, 3)), - &QueryTerm::Arg(_) => { - let call = ControlInstruction::ArgCall; - code.push(Line::Control(call)); - }, - &QueryTerm::CallN(ref terms) => { - let call = ControlInstruction::CallN(terms.len()); - code.push(Line::Control(call)); - }, - &QueryTerm::Catch(_) => - code.push(Line::Control(ControlInstruction::CatchCall)), - &QueryTerm::Compare(_) => - code.push(Line::Control(ControlInstruction::CompareCall)), - &QueryTerm::CompareTerm(qt, _) => - code.push(Line::Control(ControlInstruction::CompareTermCall(qt))), - &QueryTerm::Display(_) => - code.push(Line::Control(ControlInstruction::DisplayCall)), - &QueryTerm::DuplicateTerm(_) => - code.push(Line::Control(ControlInstruction::DuplicateTermCall)), - &QueryTerm::Eq(_) => - code.push(Line::Control(ControlInstruction::EqCall)), - &QueryTerm::Ground(_) => - code.push(Line::Control(ControlInstruction::GroundCall)), - &QueryTerm::Functor(_) => - code.push(Line::Control(ControlInstruction::FunctorCall)), - &QueryTerm::Inlined(_) => - code.push(proceed!()), &QueryTerm::Jump(ref vars) => { code.push(jmp_call!(vars.len(), 0)); }, - &QueryTerm::NotEq(_) => - code.push(Line::Control(ControlInstruction::NotEqCall)), - &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => { - let call = ControlInstruction::Call(atom.clone(), 0, pvs); - code.push(Line::Control(call)); - }, - &QueryTerm::Term(Term::Clause(_, ref atom, ref terms, _)) => { - let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs); - code.push(Line::Control(call)); - }, - &QueryTerm::Throw(_) => - code.push(Line::Control(ControlInstruction::ThrowCall)), + &QueryTerm::Clause(_, ref ct, ref terms) => + match ct { + &ClauseType::CallWithInferenceLimit => + code.push(goto_call!(393, 3)), + &ClauseType::SetupCallCleanup => + code.push(goto_call!(294, 3)), + &ClauseType::Arg => { + let call = ControlInstruction::ArgCall; + code.push(Line::Control(call)); + }, + &ClauseType::CallN => { + let call = ControlInstruction::CallN(terms.len()); + code.push(Line::Control(call)); + }, + &ClauseType::Catch => + code.push(Line::Control(ControlInstruction::CatchCall)), + &ClauseType::Compare => + code.push(Line::Control(ControlInstruction::CompareCall)), + &ClauseType::CompareTerm(qt) => + code.push(Line::Control(ControlInstruction::CompareTermCall(qt))), + &ClauseType::Display => + code.push(Line::Control(ControlInstruction::DisplayCall)), + &ClauseType::DuplicateTerm => + code.push(Line::Control(ControlInstruction::DuplicateTermCall)), + &ClauseType::Eq => + code.push(Line::Control(ControlInstruction::EqCall)), + &ClauseType::Ground => + code.push(Line::Control(ControlInstruction::GroundCall)), + &ClauseType::Functor => + code.push(Line::Control(ControlInstruction::FunctorCall)), + &ClauseType::Inlined(_) => + code.push(proceed!()), + &ClauseType::NotEq => + code.push(Line::Control(ControlInstruction::NotEqCall)), + &ClauseType::Named(ref name) | &ClauseType::Op(ref name, _) => { + let call = ControlInstruction::Call(name.clone(), terms.len(), pvs); + code.push(Line::Control(call)); + }, + &ClauseType::Throw => + code.push(Line::Control(ControlInstruction::ThrowCall)), + _ => {} + }, _ => {} } } @@ -344,11 +331,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> dealloc_index } - fn compile_inlined(&mut self, term: &'a InlinedQueryTerm, term_loc: GenContext, code: &mut Code) + fn compile_inlined(&mut self, ct: InlinedClauseType, terms: &'a Vec>, + term_loc: GenContext, code: &mut Code) -> Result<(), ParserError> { - match term { - &InlinedQueryTerm::CompareNumber(cmp, ref terms) => { + match ct { + 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)?; @@ -359,8 +347,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> at_1.unwrap_or(interm!(1)), at_2.unwrap_or(interm!(2)))); }, - &InlinedQueryTerm::IsAtomic(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsAtomic => + match terms[0].as_ref() { &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => { code.push(fail!()); }, @@ -372,8 +360,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(is_atomic!(r)); } }, - &InlinedQueryTerm::IsCompound(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsCompound => + match terms[0].as_ref() { &Term::Clause(..) | &Term::Cons(..) => { code.push(succeed!()); }, @@ -385,8 +373,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(fail!()); } }, - &InlinedQueryTerm::IsRational(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsRational => + match terms[0].as_ref() { &Term::Constant(_, Constant::Number(Number::Rational(_))) => { code.push(succeed!()); }, @@ -398,8 +386,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(fail!()); } }, - &InlinedQueryTerm::IsFloat(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsFloat => + match terms[0].as_ref() { &Term::Constant(_, Constant::Number(Number::Float(_))) => { code.push(succeed!()); }, @@ -411,8 +399,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(fail!()); } }, - &InlinedQueryTerm::IsString(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsString => + match terms[0].as_ref() { &Term::Constant(_, Constant::String(_)) => { code.push(succeed!()); }, @@ -424,8 +412,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(fail!()); } }, - &InlinedQueryTerm::IsNonVar(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsNonVar => + match terms[0].as_ref() { &Term::AnonVar => { code.push(fail!()); }, @@ -437,8 +425,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(succeed!()); } }, - &InlinedQueryTerm::IsInteger(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsInteger => + match terms[0].as_ref() { &Term::Constant(_, Constant::Number(Number::Integer(_))) => { code.push(succeed!()); }, @@ -450,8 +438,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> code.push(fail!()); }, }, - &InlinedQueryTerm::IsVar(ref inner_term) => - match inner_term[0].as_ref() { + InlinedClauseType::IsVar => + match terms[0].as_ref() { &Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => { code.push(fail!()); }, @@ -488,14 +476,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> GenContext::Last(chunk_num) }; + let term = if let &ChunkedTerm::BodyTerm(ref term) = term { + Ok(term) + } else { + Err(ParserError::InadmissibleQueryTerm) + }?; + match *term { &QueryTerm::Cut => code.push(if chunk_num == 0 { Line::Cut(CutInstruction::NeckCut) } else { Line::Cut(CutInstruction::Cut(perm_v!(1))) - }), - &QueryTerm::Is(ref terms) => { + }), + &QueryTerm::Clause(_, ClauseType::Is, ref terms) => { let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; code.append(&mut acode); @@ -510,7 +504,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> if !target.is_empty() { code.push(Line::Query(target)); } - + code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1)))); }, &Term::Constant(_, ref c @ Constant::Number(_)) => { @@ -524,8 +518,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> } } }, - &QueryTerm::Inlined(ref term) => - try!(self.compile_inlined(term, term_loc, code)), + &QueryTerm::Clause(_, ClauseType::Inlined(ct), ref terms) => + try!(self.compile_inlined(ct, terms, term_loc, code)), _ => { let num_perm_vars = if chunk_num == 0 { conjunct_info.perm_vars() @@ -535,7 +529,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed); }, - }; + }; } self.marker.reset_contents(); @@ -559,10 +553,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) { - // add a proceed to bookend any trailing inlines or cuts. + // add a proceed to bookend any trailing cuts. match toc { - &QueryTerm::Inlined(_) | &QueryTerm::Cut => - code.push(proceed!()), + &QueryTerm::Cut => code.push(proceed!()), _ => {} }; @@ -579,42 +572,37 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); - let &Rule { head: (ref p0, ref p1), ref clauses } = rule; + let &Rule { head: (_, ref args, ref p1), ref clauses } = rule; let mut code = Vec::new(); - if let &QueryTerm::Term(ref term) = p0 { - self.marker.reset_arg(term.arity()); - self.compile_seq_prelude(&conjunct_info, &mut code); + self.marker.reset_arg(args.len()); + self.compile_seq_prelude(&conjunct_info, &mut code); - if let &Term::Clause(..) = term { - let iter = FactInstruction::iter(term); - let fact = self.compile_target(iter, GenContext::Head, false); + let iter = FactIterator::from_rule_head_clause(args); + let fact = self.compile_target(iter, GenContext::Head, false); - if !fact.is_empty() { - code.push(Line::Fact(fact)); - } - } + if !fact.is_empty() { + code.push(Line::Fact(fact)); + } - let iter = ChunkedIterator::from_rule_body(p1, clauses); - try!(self.compile_seq(iter, &conjunct_info, &mut code, false)); + let iter = ChunkedIterator::from_rule_body(p1, clauses); + try!(self.compile_seq(iter, &conjunct_info, &mut code, false)); - if conjunct_info.allocates() { - let index = if let &Line::Control(_) = code.last().unwrap() { - code.len() - 2 - } else { - code.len() - 1 - }; + if conjunct_info.allocates() { + let index = if let &Line::Control(_) = code.last().unwrap() { + code.len() - 2 + } else { + code.len() - 1 + }; - if let &mut Line::Query(ref mut query) = &mut code[index] { - conjunct_info.perm_vs.mark_unsafe_vars_in_rule(term, query); - } + if let &mut Line::Query(ref mut query) = &mut code[index] { + let head_iter = FactIterator::from_rule_head_clause(args); + conjunct_info.perm_vs.mark_unsafe_vars_in_rule(head_iter, query); } - - Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1)); - Ok(code) - } else { - Err(ParserError::InvalidRuleHead) } + + Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1)); + Ok(code) } fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) diff --git a/src/prolog/debray_allocator.rs b/src/prolog/debray_allocator.rs index 0e86efe9..4fda7415 100644 --- a/src/prolog/debray_allocator.rs +++ b/src/prolog/debray_allocator.rs @@ -210,7 +210,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a> match lvl { Level::Deep => target.push(Target::subterm_to_variable(r)), - Level::Shallow => { + Level::Root | Level::Shallow => { let k = self.arg_c; self.arg_c += 1; @@ -218,12 +218,9 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a> } }; } - - fn mark_non_var(&mut self, - lvl: Level, - term_loc: GenContext, - cell: &Cell, - target: &mut Vec) + + fn mark_non_var(&mut self, lvl: Level, term_loc: GenContext, + cell: &Cell, target: &mut Vec) where Target: CompilationTarget<'a> { let r = cell.get(); @@ -270,7 +267,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a> }; match lvl { - Level::Shallow => { + Level::Root | Level::Shallow => { let k = self.arg_c; if self.is_curr_arg_distinct_from(var) { diff --git a/src/prolog/fixtures.rs b/src/prolog/fixtures.rs index 7d09b5bd..3b9abcf6 100644 --- a/src/prolog/fixtures.rs +++ b/src/prolog/fixtures.rs @@ -1,4 +1,5 @@ use prolog::ast::*; +use prolog::iterators::*; use std::cell::Cell; use std::collections::{BTreeMap, BTreeSet, HashMap}; @@ -275,9 +276,9 @@ impl<'a> VariableFixtures<'a> } } - fn mark_head_vars_as_safe(&self, head: &Term, unsafe_vars: &mut HashMap) + fn mark_head_vars_as_safe(&self, head_iter: FactIterator<'a>, unsafe_vars: &mut HashMap) { - for term_ref in head.breadth_first_iter() { + for term_ref in head_iter { match term_ref { TermRef::Var(Level::Shallow, cell, _) => { unsafe_vars.remove(&cell.get().norm()); @@ -294,12 +295,12 @@ impl<'a> VariableFixtures<'a> self.mark_unsafe_vars(&mut unsafe_vars, query); } - pub fn mark_unsafe_vars_in_rule(&self, head: &Term, query: &mut CompiledQuery) + pub fn mark_unsafe_vars_in_rule(&self, head_iter: FactIterator<'a>, query: &mut CompiledQuery) { let mut unsafe_vars = HashMap::new(); self.record_unsafe_vars(&mut unsafe_vars); - self.mark_head_vars_as_safe(head, &mut unsafe_vars); + self.mark_head_vars_as_safe(head_iter, &mut unsafe_vars); self.mark_unsafe_vars(&mut unsafe_vars, query); } } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 07ddbd2e..21e568ce 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -1,13 +1,12 @@ use prolog::ast::*; use prolog::heap_iter::*; -use prolog::tabled_rc::*; use std::cell::Cell; use std::rc::Rc; #[derive(Clone)] pub enum TokenOrRedirect { - Atom(TabledRc), + Atom(ClauseName), Redirect, Open, Close, @@ -21,7 +20,7 @@ pub enum TokenOrRedirect { pub trait HeapCellValueFormatter { // this function belongs to the display predicate formatter, which it uses // to format all clauses. - fn format_struct(&self, arity: usize, name: TabledRc, state_stack: &mut Vec) + fn format_struct(&self, arity: usize, name: ClauseName, state_stack: &mut Vec) { state_stack.push(TokenOrRedirect::Close); @@ -38,7 +37,7 @@ pub trait HeapCellValueFormatter { // this can be overloaded to handle special cases, falling back on the default of // format_struct when convenient. - fn format_clause(&self, usize, TabledRc, Option, &mut Vec); + fn format_clause(&self, usize, ClauseType, &mut Vec); } pub trait HeapCellValueOutputter { @@ -95,18 +94,16 @@ impl HeapCellValueOutputter for PrinterOutputter { pub struct DisplayFormatter {} impl HeapCellValueFormatter for DisplayFormatter { - fn format_clause(&self, arity: usize, name: TabledRc, fixity: Option, - state_stack: &mut Vec) + fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec) { - if fixity.is_some() { + if ct.fixity().is_some() { let mut new_name = String::from("'"); - new_name += name.as_ref(); + new_name += ct.name().as_str(); new_name += "'"; - - let name = TabledRc::new(new_name, name.table()); - self.format_struct(arity, name, state_stack); + + self.format_struct(arity, ct.name(), state_stack); } else { - self.format_struct(arity, name, state_stack); + self.format_struct(arity, ct.name(), state_stack); } } } @@ -114,31 +111,30 @@ impl HeapCellValueFormatter for DisplayFormatter { pub struct TermFormatter {} impl HeapCellValueFormatter for TermFormatter { - fn format_clause(&self, arity: usize, name: TabledRc, fixity: Option, - state_stack: &mut Vec) + fn format_clause(&self, arity: usize, ct: ClauseType, state_stack: &mut Vec) { - if let Some(fixity) = fixity { + if let Some(fixity) = ct.fixity() { match fixity { Fixity::Post => { - state_stack.push(TokenOrRedirect::Atom(name)); + 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(name)); + state_stack.push(TokenOrRedirect::Atom(ct.name())); }, Fixity::In => { state_stack.push(TokenOrRedirect::Redirect); state_stack.push(TokenOrRedirect::Space); - state_stack.push(TokenOrRedirect::Atom(name)); + state_stack.push(TokenOrRedirect::Atom(ct.name())); state_stack.push(TokenOrRedirect::Space); state_stack.push(TokenOrRedirect::Redirect); } } } else { - self.format_struct(arity, name, state_stack); + self.format_struct(arity, ct.name(), state_stack); } } } @@ -161,8 +157,10 @@ impl<'a, Formatter: HeapCellValueFormatter, Outputter: HeapCellValueOutputter> fn handle_heap_term(&mut self, heap_val: HeapCellValue) { match heap_val { - HeapCellValue::NamedStr(arity, name, fixity) => - self.formatter.format_clause(arity, name, fixity, &mut self.state_stack), + HeapCellValue::NamedStr(arity, name, fixity) => { + let ct = ClauseType::from(name, arity, fixity); + self.formatter.format_clause(arity, ct, &mut self.state_stack) + }, HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => if !self.at_cdr("") { self.outputter.append("[]"); diff --git a/src/prolog/indexing.rs b/src/prolog/indexing.rs index 48a26d98..384a343f 100644 --- a/src/prolog/indexing.rs +++ b/src/prolog/indexing.rs @@ -1,5 +1,4 @@ use prolog::ast::*; -use prolog::tabled_rc::*; use std::collections::{HashMap, VecDeque}; use std::hash::Hash; @@ -12,7 +11,7 @@ enum IntIndex { pub struct CodeOffsets { pub constants: HashMap, pub lists: ThirdLevelIndex, - pub structures: HashMap<(TabledRc, usize), ThirdLevelIndex> + pub structures: HashMap<(ClauseName, usize), ThirdLevelIndex> } impl CodeOffsets { @@ -145,7 +144,7 @@ impl CodeOffsets { } } - fn switch_on_structure(str_ind: HashMap<(TabledRc, usize), ThirdLevelIndex>, + fn switch_on_structure(str_ind: HashMap<(ClauseName, usize), ThirdLevelIndex>, prelude: &mut CodeDeque) -> IntIndex { diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 3a5847eb..8418d88e 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -13,21 +13,21 @@ use termion::event::Key; use std::io::{Write, stdin, stdout}; use std::fmt; +impl fmt::Display for ClauseName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + impl fmt::Display for FactInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &FactInstruction::GetConstant(Level::Shallow, ref constant, ref r) => - write!(f, "get_constant {}, A{}", constant, r.reg_num()), - &FactInstruction::GetConstant(Level::Deep, ref constant, ref r) => - write!(f, "get_constant {}, {}", constant, r), - &FactInstruction::GetList(Level::Shallow, ref r) => - write!(f, "get_list A{}", r.reg_num()), - &FactInstruction::GetList(Level::Deep, ref r) => - write!(f, "get_list {}", r), - &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r, _) => - write!(f, "get_structure {}/{}, {}", name, arity, r), - &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r, _) => - write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()), + &FactInstruction::GetConstant(lvl, ref constant, ref r) => + write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num()), + &FactInstruction::GetList(lvl, ref r) => + write!(f, "get_list {}{}", lvl, r.reg_num()), + &FactInstruction::GetStructure(ref ct, ref arity, ref r) => + write!(f, "get_structure {}/{}, {}", ct.name(), arity, r), &FactInstruction::GetValue(ref x, ref a) => write!(f, "get_value {}, A{}", x, a), &FactInstruction::GetVariable(ref x, ref a) => @@ -51,18 +51,12 @@ impl fmt::Display for QueryInstruction { match self { &QueryInstruction::GetVariable(ref x, ref a) => write!(f, "query:get_variable {}, A{}", x, a), - &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) => - write!(f, "put_constant {}, A{}", constant, r.reg_num()), - &QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) => - write!(f, "put_constant {}, {}", constant, r), - &QueryInstruction::PutList(Level::Shallow, ref r) => - write!(f, "put_list A{}", r.reg_num()), - &QueryInstruction::PutList(Level::Deep, ref r) => - write!(f, "put_list {}", r), - &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r, _) => - write!(f, "put_structure {}/{}, {}", name, arity, r), - &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r, _) => - write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()), + &QueryInstruction::PutConstant(lvl, ref constant, ref r) => + write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num()), + &QueryInstruction::PutList(lvl, ref r) => + write!(f, "put_list {}{}", lvl, r.reg_num()), + &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => + write!(f, "put_structure {}/{}, {}", ct.name(), arity, r), &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a), &QueryInstruction::PutValue(ref x, ref a) => @@ -382,7 +376,7 @@ impl fmt::Display for CutInstruction { impl fmt::Display for Level { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Level::Shallow => write!(f, "A"), + &Level::Root | &Level::Shallow => write!(f, "A"), &Level::Deep => write!(f, "X") } } @@ -531,7 +525,7 @@ fn compile_query<'a>(terms: &'a Vec, queue: &'a Vec) let mut code = try!(cg.compile_query(terms)); compile_appendix(&mut code, queue)?; - + Ok((code, cg.take_vars())) } diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 600ed116..c29fec66 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -10,21 +10,31 @@ pub struct QueryIterator<'a> { impl<'a> QueryIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_stack.push(TermIterState::to_state(lvl, term)); + self.state_stack.push(TermIterState::subterm_to_state(lvl, term)); + } + + fn from_rule_head_clause(terms: &'a Vec>) -> Self { + let state_stack = terms.iter().rev() + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .collect(); + + QueryIterator { state_stack } } fn from_term(term: &'a Term) -> Self { let state = match term { &Term::AnonVar => return QueryIterator { state_stack: vec![] }, - &Term::Clause(_, ref name, ref terms, _) => - TermIterState::Clause(0, ClauseType::Root(name), terms), + &Term::Clause(ref r, ref name, ref terms, fixity) => + TermIterState::Clause(Level::Root, 0, r, + ClauseType::from(name.clone(), terms.len(), fixity), + terms), &Term::Cons(..) => return QueryIterator { state_stack: vec![] }, &Term::Constant(_, _) => return QueryIterator { state_stack: vec![] }, &Term::Var(ref cell, ref var) => - TermIterState::Var(Level::Shallow, cell, var) + TermIterState::Var(Level::Root, cell, var) }; QueryIterator { state_stack: vec![state] } @@ -32,87 +42,18 @@ impl<'a> QueryIterator<'a> { fn new(term: &'a QueryTerm) -> Self { match term { - &QueryTerm::CallN(ref terms) => { - let state = TermIterState::Clause(1, ClauseType::CallN, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::CallWithInferenceLimit(ref terms) => { - let ct = ClauseType::CallWithInferenceLimit; - let state = TermIterState::Clause(0, ct, terms); - - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Catch(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Catch, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::DuplicateTerm(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::DuplicateTerm, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Arg(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Arg, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::SetupCallCleanup(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::SetupCallCleanup, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Eq(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Eq, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Functor(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Functor, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Display(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Display, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Ground(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Ground, terms); + &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms) => { + let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms); QueryIterator { state_stack: vec![state] } }, - &QueryTerm::Inlined(InlinedQueryTerm::CompareNumber(qt, ref terms)) => { - let state = TermIterState::Clause(0, ClauseType::CompareNumber(qt), terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Compare(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Compare, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::CompareTerm(qt, ref terms) => { - let state = TermIterState::Clause(0, ClauseType::CompareTerm(qt), terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Is(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::Is, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsInteger(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsNonVar(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsFloat(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsRational(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsCompound(ref terms)) - | &QueryTerm::Inlined(InlinedQueryTerm::IsString(ref terms)) => - Self::from_term(terms[0].as_ref()), - &QueryTerm::NotEq(ref terms) => { - let state = TermIterState::Clause(0, ClauseType::NotEq, terms); - QueryIterator { state_stack: vec![state] } - }, - &QueryTerm::Term(ref term) => - Self::from_term(term), - &QueryTerm::Throw(ref term) => { - let state = TermIterState::Clause(0, ClauseType::Throw, term); + &QueryTerm::Clause(ref cell, ref ct, ref terms) => { + let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms); QueryIterator { state_stack: vec![state] } }, &QueryTerm::Cut => QueryIterator { state_stack: vec![] }, &QueryTerm::Jump(ref vars) => { let state_stack = vars.iter().rev().map(|t| { - TermIterState::to_state(Level::Shallow, t) + TermIterState::subterm_to_state(Level::Shallow, t) }).collect(); QueryIterator { state_stack } @@ -121,12 +62,6 @@ impl<'a> QueryIterator<'a> { } } -impl QueryTerm { - pub fn post_order_iter<'a>(&'a self) -> QueryIterator<'a> { - QueryIterator::new(self) - } -} - impl<'a> Iterator for QueryIterator<'a> { type Item = TermRef<'a>; @@ -135,25 +70,30 @@ impl<'a> Iterator for QueryIterator<'a> { match iter_state { TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)), - TermIterState::Clause(child_num, ct, child_terms) => { + TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { if child_num == child_terms.len() { match ct { ClauseType::CallN => self.push_subterm(Level::Shallow, child_terms[0].as_ref()), - ClauseType::Deep(..) => - return Some(TermRef::Clause(ct, child_terms)), + ClauseType::Named(..) | ClauseType::Op(..) => + return match lvl { + Level::Root => None, + lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)) + }, _ => return None }; } else { - self.state_stack.push(TermIterState::Clause(child_num + 1, ct, child_terms)); - self.push_subterm(ct.level_of_subterms(), child_terms[child_num].as_ref()); + self.state_stack.push(TermIterState::Clause(lvl, child_num + 1, + cell, ct, child_terms)); + self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref()); } }, TermIterState::InitialCons(lvl, cell, head, tail) => { self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail)); - self.push_subterm(Level::Deep, tail); - self.push_subterm(Level::Deep, head); + + self.push_subterm(lvl.child_level(), tail); + self.push_subterm(lvl.child_level(), head); }, TermIterState::FinalCons(lvl, cell, head, tail) => return Some(TermRef::Cons(lvl, cell, head, tail)), @@ -174,24 +114,31 @@ pub struct FactIterator<'a> { impl<'a> FactIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_queue.push_back(TermIterState::to_state(lvl, term)); + self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term)); + } + + pub fn from_rule_head_clause(terms: &'a Vec>) -> Self { + let state_queue = terms.iter() + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .collect(); + + FactIterator { state_queue } } - fn new(term: &'a Term) -> FactIterator<'a> { + fn new(term: &'a Term) -> Self { let states = match term { &Term::AnonVar => - vec![TermIterState::AnonVar(Level::Shallow)], - &Term::Clause(.., ref name, ref terms, _) => - vec![TermIterState::Clause(0, ClauseType::Root(name), terms)], + vec![TermIterState::AnonVar(Level::Root)], + &Term::Clause(ref cell, ref name, ref terms, fixity) => { + let ct = ClauseType::from(name.clone(), terms.len(), fixity); + vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] + }, &Term::Cons(ref cell, ref head, ref tail) => - vec![TermIterState::InitialCons(Level::Shallow, - cell, - head.as_ref(), - tail.as_ref())], + vec![TermIterState::InitialCons(Level::Root, cell, head.as_ref(), tail.as_ref())], &Term::Constant(ref cell, ref constant) => - vec![TermIterState::Constant(Level::Shallow, cell, constant)], + vec![TermIterState::Constant(Level::Root, cell, constant)], &Term::Var(ref cell, ref var) => - vec![TermIterState::Var(Level::Shallow, cell, var)] + vec![TermIterState::Var(Level::Root, cell, var)] }; FactIterator { state_queue: VecDeque::from(states) } @@ -206,16 +153,14 @@ impl<'a> Iterator for FactIterator<'a> { match state { TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)), - TermIterState::Clause(_, ct, child_terms) => { + TermIterState::Clause(lvl, _, cell, ct, child_terms) => { for child_term in child_terms { - self.push_subterm(ct.level_of_subterms(), child_term); + self.push_subterm(lvl.child_level(), child_term); } - match ct { - ClauseType::Deep(..) => - return Some(TermRef::Clause(ct, child_terms)), - _ => - continue + match lvl { + Level::Root => continue, + _ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)) }; }, TermIterState::InitialCons(lvl, cell, head, tail) => { @@ -246,10 +191,32 @@ impl Term { } } +pub enum ChunkedTerm<'a> { + HeadClause(ClauseName, &'a Vec>), + BodyTerm(&'a QueryTerm) +} + +impl QueryTerm { + pub fn post_order_iter<'a>(&'a self) -> QueryIterator<'a> { + QueryIterator::new(self) + } +} + +impl<'a> ChunkedTerm<'a> { + pub fn post_order_iter(&self) -> QueryIterator<'a> { + match self { + &ChunkedTerm::BodyTerm(ref qt) => + QueryIterator::new(qt), + &ChunkedTerm::HeadClause(_, terms) => + QueryIterator::from_rule_head_clause(terms) + } + } +} + pub struct ChunkedIterator<'a> { - term_loc: GenContext, - iter: Box + 'a>, + pub chunk_num: usize, + iter: Box> + 'a>, deep_cut_encountered: bool } @@ -258,19 +225,19 @@ impl<'a> ChunkedIterator<'a> pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self { ChunkedIterator { - term_loc: GenContext::Last(0), - iter: Box::new(terms.iter()), + chunk_num: 0, + iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))), deep_cut_encountered: false } } pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec) -> Self { - let inner_iter = Box::new(once(p1)); - let iter = inner_iter.chain(clauses.iter()); + let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); + let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); ChunkedIterator { - term_loc: GenContext::Last(0), + chunk_num: 0, iter: Box::new(iter), deep_cut_encountered: false } @@ -278,14 +245,14 @@ impl<'a> ChunkedIterator<'a> pub fn from_rule(rule: &'a Rule) -> Self { - let &Rule { head: (ref p0, ref p1), ref clauses } = rule; + let &Rule { head: (ref name, ref args, ref p1), ref clauses } = rule; - let iter = once(p0); - let inner_iter = Box::new(once(p1)); - let iter = iter.chain(inner_iter.chain(clauses.iter())); + let iter = once(ChunkedTerm::HeadClause(name.clone(), args)); + let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); + let iter = iter.chain(inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)))); ChunkedIterator { - term_loc: GenContext::Head, + chunk_num: 0, iter: Box::new(iter), deep_cut_encountered: false, } @@ -295,15 +262,7 @@ impl<'a> ChunkedIterator<'a> self.deep_cut_encountered } - pub fn at_rule_head(&self) -> bool { - self.term_loc == GenContext::Head - } - - pub fn chunk_num(&self) -> usize { - self.term_loc.chunk_num() - } - - fn take_chunk(&mut self, term: &'a QueryTerm) -> (usize, usize, Vec<&'a QueryTerm>) + fn take_chunk(&mut self, term: ChunkedTerm<'a>) -> (usize, usize, Vec>) { let mut arity = 0; let mut item = Some(term); @@ -311,81 +270,39 @@ impl<'a> ChunkedIterator<'a> while let Some(term) = item { match term { - &QueryTerm::Jump(ref vars) => { + ChunkedTerm::HeadClause(..) => + result.push(term), + ChunkedTerm::BodyTerm(&QueryTerm::Jump(ref vars)) => { result.push(term); arity = vars.len(); break; }, - &QueryTerm::CompareTerm(..) => { - result.push(term); - arity = 2; - break; - }, - &QueryTerm::Term(ref inner_term) => - if let GenContext::Head = self.term_loc { - result.push(term); - self.term_loc = GenContext::Last(0); - } else { - result.push(term); - - if inner_term.is_callable() { - arity = inner_term.arity(); - break; - } - }, - &QueryTerm::SetupCallCleanup(_) | &QueryTerm::Compare(_) => { - result.push(term); - arity = 3; - break; - }, - &QueryTerm::CallN(ref child_terms) => { - result.push(term); - arity = child_terms.len() + 1; - break; - }, - &QueryTerm::Catch(ref child_terms) - | &QueryTerm::Throw(ref child_terms) => { + ChunkedTerm::BodyTerm(&QueryTerm::Cut) => { result.push(term); - arity = child_terms.len(); - break; - }, - &QueryTerm::Ground(_) | &QueryTerm::Display(_) => { - result.push(term); - arity = 1; - break; + + if self.chunk_num > 0 { + self.deep_cut_encountered = true; + } }, - &QueryTerm::Arg(_) - | &QueryTerm::Functor(_) - | &QueryTerm::CallWithInferenceLimit(_) => { + ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), _)) => + result.push(term), + ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::CallN, ref subterms)) => { result.push(term); - arity = 3; + arity = subterms.len() + 1; break; }, - &QueryTerm::Eq(_) | &QueryTerm::NotEq(_) - | &QueryTerm::Is(_) | &QueryTerm::DuplicateTerm(_) => { + ChunkedTerm::BodyTerm(qt) => { result.push(term); - arity = 2; + arity = qt.arity(); break; - }, - &QueryTerm::Inlined(_) => - result.push(term), - &QueryTerm::Cut => { - result.push(term); - - if self.term_loc.chunk_num() > 0 { - self.deep_cut_encountered = true; - } - }, + } }; item = self.iter.next(); } - let chunk_num = self.term_loc.chunk_num(); - - if let &mut GenContext::Last(ref mut chunk_num) = &mut self.term_loc { - *chunk_num += 1; - } + let chunk_num = self.chunk_num; + self.chunk_num += 1; (chunk_num, arity, result) } @@ -394,7 +311,7 @@ impl<'a> ChunkedIterator<'a> impl<'a> Iterator for ChunkedIterator<'a> { // the chunk number, last term arity, and vector of references. - type Item = (usize, usize, Vec<&'a QueryTerm>); + type Item = (usize, usize, Vec>); fn next(&mut self) -> Option { self.iter.next().map(|term| self.take_chunk(term)) diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 8368984d..55e5fcc8 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -185,7 +185,7 @@ pub(crate) type CallResult = Result<(), Vec>; pub(crate) trait CallPolicy: Any { fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir, - name: TabledRc, arity: usize) + name: ClauseName, arity: usize) -> CallResult { let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1); @@ -204,7 +204,7 @@ pub(crate) trait CallPolicy: Any { } fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir, - name: TabledRc, arity: usize) + name: ClauseName, arity: usize) -> CallResult { let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1); @@ -351,20 +351,19 @@ pub(crate) struct DefaultCallPolicy {} impl CallPolicy for DefaultCallPolicy {} -pub(crate) struct CallWithInferenceLimitCallPolicy { - atom_tbl: TabledData, +pub(crate) struct CallWithInferenceLimitCallPolicy { pub(crate) prev_policy: Box, count: BigUint, limits: Vec<(BigUint, usize)> } impl CallWithInferenceLimitCallPolicy { - pub(crate) fn new_in_place(atom_tbl: TabledData, policy: &mut Box) + pub(crate) fn new_in_place(policy: &mut Box) { let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); swap(&mut prev_policy, policy); - let new_policy = CallWithInferenceLimitCallPolicy { atom_tbl, prev_policy, + let new_policy = CallWithInferenceLimitCallPolicy { prev_policy, count: BigUint::zero(), limits: vec![] }; *policy = Box::new(new_policy); @@ -373,15 +372,13 @@ impl CallWithInferenceLimitCallPolicy { fn increment(&mut self) -> CallResult { if let Some(&(ref limit, bp)) = self.limits.last() { if self.count == *limit { - return Err(functor!(self.atom_tbl, - "inference_limit_exceeded", - 1, + return Err(functor!("inference_limit_exceeded", 1, [HeapCellValue::Addr(Addr::Con(Constant::Usize(bp)))])); } else { self.count += BigUint::one(); } } - + Ok(()) } @@ -422,7 +419,7 @@ impl CallWithInferenceLimitCallPolicy { impl CallPolicy for CallWithInferenceLimitCallPolicy { fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir, - name: TabledRc, arity: usize) + name: ClauseName, arity: usize) -> CallResult { self.prev_policy.try_call(machine_st, code_dir, name, arity)?; @@ -430,7 +427,7 @@ impl CallPolicy for CallWithInferenceLimitCallPolicy { } fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir, - name: TabledRc, arity: usize) + name: ClauseName, arity: usize) -> CallResult { self.prev_policy.try_execute(machine_st, code_dir, name, arity)?; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index ca2c2827..5d5059bf 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -269,13 +269,7 @@ impl MachineState { match item { Addr::Con(Constant::Number(n)) => Ok(n), - _ => { - let atom_tbl = self.atom_tbl.clone(); - Err(functor!(self.atom_tbl, - "instantiation_error", - 1, - [heap_atom!("(is)/2", atom_tbl)])) - } + _ => Err(functor!("instantiation_error", 1, [heap_atom!("(is)/2")])) } }, &ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()), @@ -292,10 +286,7 @@ impl MachineState { if let Some(r) = Ratio::from_float(fl.into_inner()) { Ok(Rc::new(r)) } else { - Err(functor!(self.atom_tbl, - "instantiation_error", - 1, - [heap_atom!("(is)/2", self.atom_tbl)])) + Err(functor!("instantiation_error", 1, [heap_atom!("(is)/2")])) }, Number::Integer(bi) => Ok(Rc::new(Ratio::from_integer((*bi).clone()))) @@ -316,9 +307,7 @@ impl MachineState { fn arith_eval_by_metacall(&self, r: RegType) -> Result> { - let instantiation_err = functor!(self.atom_tbl.clone(), "instantiation_error", 1, - [heap_atom!("(is)/2", self.atom_tbl.clone())]); - + let instantiation_err = functor!("instantiation_error", 1, [heap_atom!("(is)/2")]); let a = self[r].clone(); if let &Addr::Con(Constant::Number(ref n)) = &a { @@ -378,8 +367,7 @@ impl MachineState { -> Result>, Vec> { if *r2 == Ratio::zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(Rc::new(&*r1 / &*r2)) } @@ -390,13 +378,11 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(Rc::new(n1.div_floor(&n2))) }, - _ => Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + _ => Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -405,22 +391,19 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(Rc::new(&*n1 / &*n2)) }, _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } fn div(&self, n1: Number, n2: Number) -> Result> { if n2.is_zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(n1 / n2) } @@ -435,8 +418,7 @@ impl MachineState { _ => Ok(Rc::new(&*n1 >> usize::max_value())) }, _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -449,8 +431,7 @@ impl MachineState { _ => Ok(Rc::new(&*n1 << usize::max_value())) }, _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -460,8 +441,7 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 ^ u_n2)), _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -471,8 +451,7 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -481,14 +460,12 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(Rc::new(n1.mod_floor(&n2))) }, _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -497,14 +474,12 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("zero_divisor", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) } else { Ok(Rc::new(&*n1 % &*n2)) }, _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -514,8 +489,7 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), _ => - Err(functor!(self.atom_tbl.clone(), "evaluation_error", 1, - [heap_atom!("expected_integer_args", self.atom_tbl.clone())])) + Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) } } @@ -661,15 +635,15 @@ impl MachineState { _ => self.fail = true }; }, - &FactInstruction::GetStructure(_, ref name, arity, reg, fixity) => { + &FactInstruction::GetStructure(ref ct, arity, reg) => { let addr = self.deref(self[reg].clone()); match self.store(addr.clone()) { Addr::Str(a) => { let result = &self.heap[a]; - if let &HeapCellValue::NamedStr(narity, ref str, _) = result { - if narity == arity && *name == *str { + if let &HeapCellValue::NamedStr(narity, ref s, _) = result { + if narity == arity && ct.name() == *s { self.s = a + 1; self.mode = MachineMode::Read; } else { @@ -681,7 +655,7 @@ impl MachineState { let h = self.heap.h; self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1))); - self.heap.push(HeapCellValue::NamedStr(arity, name.clone(), fixity)); + self.heap.push(HeapCellValue::NamedStr(arity, ct.name(), ct.fixity())); self.bind(addr.as_var().unwrap(), Addr::HeapCell(h)); @@ -858,10 +832,10 @@ impl MachineState { self[reg] = Addr::Con(constant.clone()), &QueryInstruction::PutList(_, reg) => self[reg] = Addr::Lis(self.heap.h), - &QueryInstruction::PutStructure(_, ref name, arity, reg, fixity) => { + &QueryInstruction::PutStructure(ref ct, arity, reg) => { let h = self.heap.h; - self.heap.push(HeapCellValue::NamedStr(arity, name.clone(), fixity)); + self.heap.push(HeapCellValue::NamedStr(arity, ct.name(), ct.fixity())); self[reg] = Addr::Str(h); }, &QueryInstruction::PutUnsafeValue(n, arg) => { @@ -979,11 +953,8 @@ impl MachineState { if let HeapCellValue::NamedStr(narity, name, _) = result { if narity + arity > 63 { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "representation_error", - 1, - [heap_atom!("exceeds_max_arity", atom_tbl)])); + self.throw_exception(functor!("representation_error", 1, + [heap_atom!("exceeds_max_arity")])); return None; } @@ -1003,16 +974,12 @@ impl MachineState { }, Addr::Con(Constant::Atom(name)) => (name, 0), Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, "instantiation_error", 0, [])); + self.throw_exception(functor!("instantiation_error")); return None; }, _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "type_error", - 2, - [heap_atom!("callable", atom_tbl), + self.throw_exception(functor!("type_error", 2, + [heap_atom!("callable"), HeapCellValue::Addr(addr)])); return None; } @@ -1065,10 +1032,7 @@ impl MachineState { _ => self.fail = true }; } else { - return Err(functor!(self.atom_tbl, - "type_error", - 1, - [heap_atom!("compound_expected", self.atom_tbl)])); + return Err(functor!("type_error", 1, [heap_atom!("compound_expected")])) } } @@ -1201,7 +1165,7 @@ impl MachineState { return Ordering::Less; } else if ar1 > ar2 { return Ordering::Greater; - } else if *n1 != *n2 { + } else if n1 != n2 { return n1.cmp(&n2); } else { continue; @@ -1210,14 +1174,14 @@ impl MachineState { continue, (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::NamedStr(ar, n, _)) | (HeapCellValue::NamedStr(ar, n, _), HeapCellValue::Addr(Addr::Lis(_))) => - if ar == 2 && *n == "." { + if ar == 2 && n.as_str() == "." { continue; } else if ar < 2 { return Ordering::Greater; } else if ar > 2 { return Ordering::Less; } else { - return n.cmp(&String::from(".")); + return n.as_str().cmp("."); }, (HeapCellValue::NamedStr(..), _) => return Ordering::Greater, @@ -1356,8 +1320,7 @@ impl MachineState { let a2 = self.store(self.deref(self[r2].clone())); if call_policy.downcast_ref::().is_err() { - CallWithInferenceLimitCallPolicy::new_in_place(self.atom_tbl.clone(), - call_policy); + CallWithInferenceLimitCallPolicy::new_in_place(call_policy); } self.p += 1; @@ -1373,13 +1336,7 @@ impl MachineState { None => panic!("install_inference_counter: should have installed \\ CallWithInferenceLimitCallPolicy.") }, - _ => { - let atom_tbl = self.atom_tbl.clone(); - self.throw_exception(functor!(atom_tbl, - "type_error", - 1, - [heap_atom!("integer_expected", atom_tbl)])) - } + _ => self.throw_exception(functor!("type_error", 1, [heap_atom!("integer_expected")])) }; }, &BuiltInInstruction::IsAtomic(r) => { @@ -1634,10 +1591,10 @@ impl MachineState { self.unify(a1, f_a); } else { - return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); + return Err(functor!("instantiation_error")); } } else { - return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); + return Err(functor!("instantiation_error")); } }, _ => { @@ -1681,7 +1638,7 @@ impl MachineState { for (v1, v2) in iter { match (v1, v2) { (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => - if ar1 != ar2 || *n1 != *n2 { + if ar1 != ar2 || n1 != n2 { return true; }, (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => @@ -1710,7 +1667,7 @@ impl MachineState { for (v1, v2) in iter { match (v1, v2) { (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => - if ar1 != ar2 || *n1 != *n2 { + if ar1 != ar2 || n1 != n2 { return true; }, (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index e6b9da46..0d012eb7 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -46,7 +46,7 @@ impl Index for Machine { impl Machine { pub fn new() -> Self { let atom_tbl = Rc::new(RefCell::new(HashSet::new())); - let (code, code_dir, op_dir) = build_code_dir(atom_tbl.clone()); + let (code, code_dir, op_dir) = build_code_dir(); Machine { ms: MachineState::new(atom_tbl), @@ -67,7 +67,7 @@ impl Machine { self.ms.atom_tbl.clone() } - pub fn add_user_code<'a>(&mut self, name: TabledRc, arity: usize, mut code: Code) + pub fn add_user_code<'a>(&mut self, name: ClauseName, arity: usize, mut code: Code) -> EvalSession<'a> { match self.code_dir.get(&(name.clone(), arity)) { @@ -165,8 +165,7 @@ impl Machine { fn query_stepper<'a>(&mut self) { - loop - { + loop { self.execute_instr(); if self.failed() { @@ -180,10 +179,8 @@ impl Machine { } } - fn record_var_places<'a>(&self, - chunk_num: usize, - alloc_locs: &AllocVarDict<'a>, - heap_locs: &mut HeapVarDict<'a>) + fn record_var_places<'a>(&self, chunk_num: usize, + alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>) { for (var, var_data) in alloc_locs { match var_data { diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 20469d64..4dc1e785 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -1,3 +1,9 @@ +macro_rules! clause_name { + ($name: expr) => ( + ClauseName::BuiltIn($name) + ) +} + macro_rules! tabled_rc { ($e:expr, $tbl:expr) => ( TabledRc::new(String::from($e), $tbl.clone()) @@ -6,7 +12,10 @@ macro_rules! tabled_rc { macro_rules! atom { ($e:expr, $tbl:expr) => ( - Constant::Atom(tabled_rc!($e, $tbl)) + Constant::Atom(ClauseName::User(tabled_rc!($e, $tbl))) + ); + ($e:expr) => ( + Constant::Atom(clause_name!($e)) ) } @@ -47,22 +56,21 @@ macro_rules! query { } macro_rules! heap_atom { + ($name:expr) => ( + HeapCellValue::Addr(Addr::Con(atom!($name))) + ); ($name:expr, $tbl:expr) => ( HeapCellValue::Addr(Addr::Con(atom!($name, $tbl))) ) } macro_rules! functor { - ($tbl:expr, $name:expr, $len:expr, [$($args:expr),*]) => {{ - if $len > 0 { - vec![ HeapCellValue::NamedStr($len, - tabled_rc!($name, $tbl), - None), - $($args),* ] - } else { - vec![ heap_atom!($name, $tbl) ] - } - }} + ($name:expr) => ( + vec![ heap_atom!($name) ] + ); + ($name:expr, $len:expr, [$($args:expr),*]) => ( + vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ] + ) } macro_rules! fact { @@ -115,8 +123,11 @@ macro_rules! put_var { } macro_rules! put_structure { - ($tbl:expr, $lvl:expr, $name:expr, $arity:expr, $r:expr, $fix:expr) => ( - QueryInstruction::PutStructure($lvl, tabled_rc!($name, $tbl), $arity, $r, $fix) + ($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => ( + QueryInstruction::PutStructure(ClauseType::Op(clause_name!($atom), $fix), $arity, $r) + ); + ($atom:expr, $arity:expr, $r:expr, None) => ( + QueryInstruction::PutStructure(ClauseType::Named(clause_name!($atom)), $arity, $r) ) } @@ -368,12 +379,11 @@ macro_rules! get_constant { } macro_rules! get_structure { - ($tbl:expr, $atom:expr, $arity:expr, $r:expr, $fix:expr) => ( - FactInstruction::GetStructure(Level::Shallow, - tabled_rc!($atom, $tbl), - $arity, - $r, - $fix) + ($atom:expr, $arity:expr, $r:expr, Some($fix:expr)) => ( + FactInstruction::GetStructure(ClauseType::Op(clause_name!($atom), $fix), $arity, $r) + ); + ($atom:expr, $arity:expr, $r:expr, None) => ( + FactInstruction::GetStructure(ClauseType::Named(clause_name!($atom)), $arity, $r) ) } diff --git a/src/prolog/parser b/src/prolog/parser index cd115d7a..5b74536d 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit cd115d7a6781a59003f0d52451319ae68988e785 +Subproject commit 5b74536d6edfc55c943f77c72a99ad00dcbd96c4 diff --git a/src/prolog/tabled_rc.rs b/src/prolog/tabled_rc.rs index dc8f7194..09d253a4 100644 --- a/src/prolog/tabled_rc.rs +++ b/src/prolog/tabled_rc.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::cmp::Ordering; use std::collections::HashSet; use std::fmt; use std::hash::{Hash, Hasher}; @@ -6,13 +7,27 @@ use std::ops::Deref; use std::rc::Rc; pub type TabledData = Rc>>>; - + #[derive(Clone)] pub struct TabledRc { atom: Rc, table: TabledData } +impl PartialOrd for TabledRc { + fn partial_cmp(&self, other: &Self) -> Option + { + Some(self.atom.cmp(&other.atom)) + } +} + +impl Ord for TabledRc { + fn cmp(&self, other: &Self) -> Ordering + { + self.atom.cmp(&other.atom) + } +} + impl PartialEq for TabledRc { fn eq(&self, other: &TabledRc) -> bool { @@ -23,9 +38,8 @@ impl PartialEq for TabledRc { impl Eq for TabledRc {} impl Hash for TabledRc { - fn hash(&self, state: &mut H) - { - self.atom.hash(state) + fn hash(&self, state: &mut H) { + self.atom.hash(state) } } @@ -40,10 +54,6 @@ impl TabledRc { TabledRc { atom, table } } - - pub fn table(&self) -> TabledData { - self.table.clone() - } } impl Drop for TabledRc { diff --git a/src/prolog/targets.rs b/src/prolog/targets.rs index 783c502e..9999c429 100644 --- a/src/prolog/targets.rs +++ b/src/prolog/targets.rs @@ -1,6 +1,5 @@ use prolog::ast::*; use prolog::iterators::*; -use prolog::tabled_rc::*; pub trait CompilationTarget<'a> { type Iterator : Iterator>; @@ -9,7 +8,7 @@ pub trait CompilationTarget<'a> { fn to_constant(Level, Constant, RegType) -> Self; fn to_list(Level, RegType) -> Self; - fn to_structure(Level, TabledRc, usize, RegType, Option) -> Self; + fn to_structure(ClauseType, usize, RegType) -> Self; fn to_void(usize) -> Self; fn is_void_instr(&self) -> bool; @@ -40,11 +39,9 @@ impl<'a> CompilationTarget<'a> for FactInstruction { FactInstruction::GetConstant(lvl, constant, reg) } - fn to_structure(lvl: Level, atom: TabledRc, arity: usize, - reg: RegType, fixity: Option) - -> Self + fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self { - FactInstruction::GetStructure(lvl, atom, arity, reg, fixity) + FactInstruction::GetStructure(ct, arity, reg) } fn to_list(lvl: Level, reg: RegType) -> Self { @@ -105,11 +102,9 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { term.post_order_iter() } - fn to_structure(lvl: Level, atom: TabledRc, arity: usize, - reg: RegType, fixity: Option) - -> Self + fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self { - QueryInstruction::PutStructure(lvl, atom, arity, reg, fixity) + QueryInstruction::PutStructure(ct, arity, r) } fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { diff --git a/src/tests.rs b/src/tests.rs index b443515b..b6b227df 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -672,8 +672,8 @@ fn test_queries_on_call_n() { let mut wam = Machine::new(); - submit(&mut wam, "maplist(Pred, []). - maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs)."); + submit(&mut wam, "maplist(_, []). + maplist(P, [X|Xs]) :- call(P, X), maplist(P, Xs)."); submit(&mut wam, "f(a). f(b). f(c)."); assert_prolog_success!(&mut wam, "?- maplist(f, [X,Y,Z]).", -- 2.54.0