RemoveInferenceCounter,
RestoreCutPolicy,
SetCutPoint(RegType),
- GetArg,
InferenceLevel,
CleanUpBlock,
EraseBall,
clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
- &SystemClauseType::GetArg => clause_name!("$get_arg"),
&SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
&SystemClauseType::EraseBall => clause_name!("$erase_ball"),
Some(SystemClauseType::RemoveInferenceCounter),
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
- ("$get_arg", 3) => Some(SystemClauseType::GetArg),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
#[derive(Copy, Clone, PartialEq)]
pub enum BuiltInClauseType {
AcyclicTerm,
+ Arg,
Compare,
CompareTerm(CompareTermQT),
CyclicTerm,
pub fn name(&self) -> ClauseName {
match self {
&BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
+ &BuiltInClauseType::Arg => clause_name!("arg"),
&BuiltInClauseType::Compare => clause_name!("compare"),
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
pub fn arity(&self) -> usize {
match self {
&BuiltInClauseType::AcyclicTerm => 1,
+ &BuiltInClauseType::Arg => 3,
&BuiltInClauseType::Compare => 2,
&BuiltInClauseType::CompareTerm(_) => 2,
&BuiltInClauseType::CyclicTerm => 1,
pub fn from(name: &str, arity: usize) -> Option<Self> {
match (name, arity) {
("acyclic_term", 1) => Some(BuiltInClauseType::AcyclicTerm),
+ ("arg", 3) => Some(BuiltInClauseType::Arg),
("compare", 3) => Some(BuiltInClauseType::Compare),
("cyclic_term", 1) => Some(BuiltInClauseType::CyclicTerm),
("@>", 2) => Some(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan)),
(\/)/2, (is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2,
(>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2,
(-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2, (==)/2, (\==)/2,
- (=..)/2, arg/3, catch/3, throw/1, true/0, false/0, length/2]).
+ catch/3, throw/1, true/0, false/0, length/2]).
% arithmetic operators.
:- op(700, xfx, is).
->(G1, G2, B) :- G2 == !, call(G1), !, '$set_cp'(B).
->(G1, G2, B) :- call(G1), '$set_cp'(B), call(G2).
-% exception handling.
+/*
+Term =.. List :-
+ atomic(Term), !,
+ List = [Term].
+Term =.. List :-
+ compound(Term), !,
+ ( functor(Term, Name, NArgs) ->
+ List = [Name|Args], '$get_args'(Args, Term, 1, NArgs)
+ ; Term = [_|_] ->
+ List = ['.'|Term] ).
+Term =.. List :-
+ var(Term), !,
+ ( List = [ATerm], atomic(ATerm) ->
+ Term = ATerm
+ ; List = [Name|Args] ->
+ functor(Term, Name, Args)).
+
+'$get_args'(Args, _, _, 0) :-
+ !, Args = [].
+'$get_args'([Arg], Func, N, N) :-
+ !, '$get_arg'(N, Func, Arg).
+'$get_args'([Arg|Args], Func, I0, N) :-
+ '$get_arg'(I0, Func, Arg), I1 is I0 + 1,
+ '$get_args'(Args, Func, I1, N).
+*/
+
+% arg.
+
+/* The old, SWI Prolog-imitative arg/3.
+
+arg(N, Functor, Arg) :- var(N), !, functor(Functor, _, Arity), arg_(N, 1, Arity, Functor, Arg).
+arg(N, Functor, Arg) :- integer(N), !, functor(Functor, _, Arity), '$get_arg'(N, Functor, Arg).
+arg(N, Functor, Arg) :- throw(error(type_error(integer, N), arg/3)).
+
+arg_(N, N, N, Functor, Arg) :- !, '$get_arg'(N, Functor, Arg).
+arg_(N, N, Arity, Functor, Arg) :- '$get_arg'(N, Functor, Arg).
+arg_(N, N0, Arity, Functor, Arg) :- N0 < Arity, N1 is N0 + 1, arg_(N, N1, Arity, Functor, Arg).
+*/
+
+% The new, ISO Prolog compliant arg/3 is implemented in Rust.
+
+% exceptions.
catch(G,C,R) :- '$get_current_block'(Bb), catch(G,C,R,Bb).
throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
-% arg.
-
-arg(N, Functor, Arg) :- var(N), !, functor(Functor, _, Arity), arg_(N, 1, Arity, Functor, Arg).
-arg(N, Functor, Arg) :- integer(N), !, functor(Functor, _, Arity), '$get_arg'(N, Functor, Arg).
-arg(N, Functor, Arg) :- throw(error(type_error(integer, N), arg/3)).
-
-arg_(N, N, N, Functor, Arg) :- !, '$get_arg'(N, Functor, Arg).
-arg_(N, N, Arity, Functor, Arg) :- '$get_arg'(N, Functor, Arg).
-arg_(N, N0, Arity, Functor, Arg) :- N0 < Arity, N1 is N0 + 1, arg_(N, N1, Arity, Functor, Arg).
-
% length.
length(Xs, N) :-
'$length_rundown'([_|Xs], N) :-
N1 is N-1,
'$length_rundown'(Xs, N1).
-
-Term =.. List :-
- atomic(Term), !,
- List = [Term].
-Term =.. List :-
- compound(Term), !,
- ( functor(Term, Name, NArgs) ->
- List = [Name|Args], '$get_args'(Args, Term, 1, NArgs)
- ; Term = [_|_] ->
- List = ['.'|Term] ).
-Term =.. List :-
- var(Term), !,
- ( List = [ATerm], atomic(ATerm) ->
- Term = ATerm
- ; List = [Name|Args] ->
- functor(Term, Name, Args)).
-
-'$get_args'(Args, _, _, 0) :-
- !, Args = [].
-'$get_args'([Arg], Func, N, N) :-
- !, '$get_arg'(N, Func, Arg).
-'$get_args'([Arg|Args], Func, I0, N) :-
- '$get_arg'(I0, Func, Arg), I1 is I0 + 1,
- '$get_args'(Args, Func, I1, N).
use prolog::heap_print::*;
use prolog::machine::machine_errors::*;
use prolog::machine::machine_state::*;
-use prolog::num::{Integer, ToPrimitive, Zero};
+use prolog::num::{Integer, Signed, ToPrimitive, Zero};
use prolog::num::bigint::{BigInt, BigUint};
use prolog::num::rational::Ratio;
use prolog::or_stack::*;
fail
}
- pub(super) fn try_get_arg(&mut self) -> CallResult
+ // arg(+N, +Term, ?Arg)
+ pub(super) fn try_arg(&mut self) -> CallResult
{
- let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
+ let stub = self.functor_stub(clause_name!("arg"), 3);
+ let n = self.store(self.deref(self[temp_v!(1)].clone()));
- if let Addr::Con(Constant::Number(Number::Integer(i))) = a1 {
- let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
+ match n {
+ Addr::HeapCell(_) | Addr::StackCell(..) => // 8.5.2.3 a)
+ return Err(self.error_form(self.instantiation_error(), stub)),
+ Addr::Con(Constant::Number(Number::Integer(n))) => {
+ if n.is_negative() {
+ // 8.5.2.3 e)
+ let n = Addr::Con(Constant::Number(Number::Integer(n)));
+ return Err(self.error_form(self.domain_error(DomainError::NotLessThanZero,
+ n),
+ stub));
+ }
+
+ let n = match n.to_usize() {
+ Some(n) => n,
+ None => {
+ self.fail = true;
+ return Ok(());
+ }
+ };
- if let Addr::Str(o) = a2 {
- match self.heap[o].clone() {
- HeapCellValue::NamedStr(arity, _, _) =>
- match i.to_usize() {
- Some(i) if 1 <= i && i <= arity => {
- let a3 = self[temp_v!(3)].clone();
- let h_a = Addr::HeapCell(o + i);
+ let term = self.store(self.deref(self[temp_v!(2)].clone()));
+ match term {
+ Addr::HeapCell(_) | Addr::StackCell(..) => // 8.5.2.3 b)
+ return Err(self.error_form(self.instantiation_error(), stub)),
+ Addr::Str(o) =>
+ match self.heap[o].clone() {
+ HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => {
+ let a3 = self[temp_v!(3)].clone();
+ let h_a = Addr::HeapCell(o + n);
+
self.unify(a3, h_a);
},
_ => self.fail = true
},
- _ => self.fail = true
- };
- } else {
- let stub = self.functor_stub(clause_name!("arg"), 3);
- return Err(self.error_form(self.type_error(ValidType::Compound, a2), stub));
- }
+ Addr::Lis(l) if n == 1 || n == 2 => {
+ let a3 = self[temp_v!(3)].clone();
+ let h_a = Addr::HeapCell(l + n - 1);
+
+ self.unify(a3, h_a);
+ },
+ _ => // 8.5.2.3 d)
+ return Err(self.error_form(self.type_error(ValidType::Compound, term),
+ stub))
+ }
+
+
+ },
+ _ => // 8.5.2.3 c)
+ return Err(self.error_form(self.type_error(ValidType::Integer, n), stub))
}
Ok(())
self.try_functor_unify_components(name, arity);
}
- pub(super) fn try_functor(&mut self) -> Result<(), MachineError> {
+ pub(super) fn try_functor(&mut self) -> CallResult {
let stub = self.functor_stub(clause_name!("functor"), 3);
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));