This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/C/terms.c

1352 lines
39 KiB
C
Raw Normal View History

2019-01-30 15:24:06 +00:00
/*************************************************************************
2019-02-01 13:14:33 +00:00
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: utilpreds.c * Last rev: 4/03/88
** mods: * comments: new utility predicates for YAP *
* *
*************************************************************************/
2019-01-30 15:24:06 +00:00
/**
* @file C/terms.c
*
* @brief applications of the tree walker pattern.
*
* @addtogroup Terms
2019-02-01 13:14:33 +00:00
*
2019-01-30 15:24:06 +00:00
* @{
2019-02-01 13:14:33 +00:00
*
2019-01-30 15:24:06 +00:00
*/
#include "absmi.h"
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
#include "YapHeap.h"
2019-02-01 13:14:33 +00:00
2019-02-06 00:08:15 +00:00
#define debug_pop_text_stack(l) [ if (to_visit != to_visit0) printf("%d\n",__LINE__); pop_text_stack(l) }
2019-01-30 15:24:06 +00:00
#include "attvar.h"
2019-02-01 13:14:33 +00:00
#include "yapio.h"
2019-01-30 15:24:06 +00:00
#ifdef HAVE_STRING_H
#include "string.h"
#endif
2019-02-05 10:31:17 +00:00
#define Malloc malloc
#define Realloc realloc
2019-02-01 13:14:33 +00:00
static int expand_vts(int args USES_REGS) {
2019-01-30 15:24:06 +00:00
UInt expand = LOCAL_Error_Size;
yap_error_number yap_errno = LOCAL_Error_TYPE;
LOCAL_Error_Size = 0;
LOCAL_Error_TYPE = YAP_NO_ERROR;
if (yap_errno == RESOURCE_ERROR_TRAIL) {
/* Trail overflow */
2019-02-01 13:14:33 +00:00
if (!Yap_growtrail(expand, false)) {
return false;
2019-01-30 15:24:06 +00:00
}
} else if (yap_errno == RESOURCE_ERROR_AUXILIARY_STACK) {
/* Aux space overflow */
2019-02-01 13:14:33 +00:00
if (expand > 4 * 1024 * 1024)
expand = 4 * 1024 * 1024;
if (!Yap_ExpandPreAllocCodeSpace(expand, NULL, true)) {
return false;
2019-01-30 15:24:06 +00:00
}
} else {
2019-02-01 13:14:33 +00:00
if (!Yap_gcl(expand, 3, ENV, gc_P(P, CP))) {
2019-01-30 15:24:06 +00:00
Yap_Error(RESOURCE_ERROR_STACK, TermNil, "in term_variables");
2019-02-01 13:14:33 +00:00
return false;
2019-01-30 15:24:06 +00:00
}
}
2019-02-01 13:14:33 +00:00
return true;
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
static inline void clean_tr(tr_fr_ptr TR0 USES_REGS) {
2019-01-30 15:24:06 +00:00
tr_fr_ptr pt0 = TR;
while (pt0 != TR0) {
Term p = TrailTerm(--pt0);
if (IsApplTerm(p)) {
CELL *pt = RepAppl(p);
#ifdef FROZEN_STACKS
pt[0] = TrailVal(pt0);
#else
pt[0] = TrailTerm(pt0 - 1);
2019-02-01 13:14:33 +00:00
pt0--;
2019-01-30 15:24:06 +00:00
#endif /* FROZEN_STACKS */
} else {
RESET_VARIABLE(p);
}
2019-02-01 13:14:33 +00:00
}
2019-01-30 15:24:06 +00:00
TR = TR0;
}
2019-02-03 21:35:12 +00:00
2019-01-30 15:24:06 +00:00
typedef struct {
2019-02-01 13:14:33 +00:00
Term old_var;
Term new_var;
} * vcell;
2019-01-30 15:24:06 +00:00
typedef struct non_single_struct_t {
CELL *ptd0;
CELL d0;
2019-02-04 10:42:23 +00:00
CELL *pt0, *pt0_end, *ptf;
2019-01-30 15:24:06 +00:00
} non_singletons_t;
2019-02-01 13:14:33 +00:00
#define WALK_COMPLEX_TERM__(LIST0, STRUCT0, PRIMI0) \
\
struct non_single_struct_t *to_visit = Malloc( \
1024 * sizeof(struct non_single_struct_t)), \
*to_visit0 = to_visit, \
*to_visit_max = to_visit + 1024; \
\
2019-02-08 09:33:07 +00:00
while (to_visit >= to_visit0) { \
2019-02-06 15:08:25 +00:00
CELL d0; \
CELL *ptd0; \
restart:\
while (pt0 < pt0_end) { \
2019-02-01 13:14:33 +00:00
++pt0; \
2019-02-06 15:08:25 +00:00
ptd0 = pt0; \
2019-02-01 13:14:33 +00:00
d0 = *ptd0; \
2019-02-06 15:08:25 +00:00
list_loop: \
2019-02-08 09:33:07 +00:00
/*fprintf(stderr, "%ld at %s\n", to_visit - to_visit0, __FUNCTION__);*/ \
2019-02-06 15:08:25 +00:00
deref_head(d0, var_in_term_unk); \
2019-02-01 13:14:33 +00:00
var_in_term_nvar : { \
if (IsPairTerm(d0)) { \
if (to_visit + 32 >= to_visit_max) { \
goto aux_overflow; \
} \
ptd0 = RepPair(d0); \
2019-02-06 15:08:25 +00:00
d0 = ptd0[0]; \
2019-02-04 01:08:18 +00:00
LIST0; \
2019-02-06 15:08:25 +00:00
if (d0 == TermFreeTerm) \
2019-02-04 01:08:18 +00:00
goto restart; \
2019-02-01 13:14:33 +00:00
to_visit->pt0 = pt0; \
to_visit->pt0_end = pt0_end; \
2019-02-06 15:08:25 +00:00
to_visit->ptd0 = ptd0; \
to_visit->d0 = d0; \
2019-02-01 13:14:33 +00:00
to_visit++; \
2019-02-06 15:08:25 +00:00
*ptd0 = TermFreeTerm; \
2019-02-01 13:14:33 +00:00
pt0 = ptd0; \
pt0_end = pt0 + 1; \
2019-02-06 15:08:25 +00:00
goto list_loop; \
2019-02-01 13:14:33 +00:00
} else if (IsApplTerm(d0)) { \
register Functor f; \
/* store the terms to visit */ \
2019-02-06 15:08:25 +00:00
ptd0 = RepAppl(d0); \
f = (Functor)(d0 = *ptd0); \
2019-02-01 13:14:33 +00:00
\
if (to_visit + 32 >= to_visit_max) { \
goto aux_overflow; \
} \
2019-02-04 01:08:18 +00:00
STRUCT0; \
2019-02-06 15:08:25 +00:00
if (IsExtensionFunctor(f) || f == FunctorDollarVar || IsAtomTerm((CELL)f)) { \
2019-02-04 01:08:18 +00:00
\
2019-02-06 15:08:25 +00:00
continue; \
2019-02-04 01:08:18 +00:00
} \
2019-02-01 13:14:33 +00:00
to_visit->pt0 = pt0; \
to_visit->pt0_end = pt0_end; \
2019-02-06 15:08:25 +00:00
to_visit->ptd0 = ptd0; \
to_visit->d0 = d0; \
2019-02-01 13:14:33 +00:00
to_visit++; \
\
2019-02-06 15:08:25 +00:00
*ptd0 = TermNil; \
Term d1 = ArityOfFunctor(f); \
pt0 = ptd0; \
pt0_end = ptd0 + d1; \
continue; \
2019-02-04 01:08:18 +00:00
} else { \
PRIMI0; \
2019-02-06 15:08:25 +00:00
continue; \
2019-02-04 01:08:18 +00:00
} \
2019-02-01 13:14:33 +00:00
derefa_body(d0, ptd0, var_in_term_unk, var_in_term_nvar);
#define WALK_COMPLEX_TERM() WALK_COMPLEX_TERM__({}, {}, {})
2019-02-06 15:08:25 +00:00
#define END_WALK() \
}\
}\
/* Do we still have compound terms to visit */ \
2019-02-08 09:33:07 +00:00
to_visit--; \
if (to_visit >= to_visit0) {\
pt0 = to_visit->pt0; \
2019-02-06 15:08:25 +00:00
pt0_end = to_visit->pt0_end;\
2019-02-08 09:33:07 +00:00
*to_visit->ptd0 = to_visit->d0; \
}\
}\
2019-02-06 15:08:25 +00:00
pop_text_stack(lvl);
2019-01-30 15:24:06 +00:00
2019-02-04 01:08:18 +00:00
#define def_aux_overflow() \
aux_overflow : { \
2019-02-01 13:14:33 +00:00
size_t d1 = to_visit - to_visit0; \
2019-02-06 15:08:25 +00:00
size_t d2 = to_visit_max - to_visit0; \
2019-02-01 13:14:33 +00:00
to_visit0 = \
Realloc(to_visit0, (d2 + 128) * sizeof(struct non_single_struct_t)); \
to_visit = to_visit0 + d1; \
to_visit_max = to_visit0 + (d2 + 128); \
pt0--; \
2019-02-04 01:08:18 +00:00
} \
2019-02-01 13:14:33 +00:00
goto restart;
#define def_trail_overflow() \
trail_overflow : { \
LOCAL_Error_TYPE = RESOURCE_ERROR_TRAIL; \
LOCAL_Error_Size = (TR - TR0) * sizeof(tr_fr_ptr *); \
clean_tr(TR0 PASS_REGS); \
HR = InitialH; \
2019-02-04 10:42:23 +00:00
pop_text_stack(lvl); \
2019-02-01 13:14:33 +00:00
return 0L; \
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
#define def_global_overflow() \
global_overflow : { \
while (to_visit > to_visit0) { \
to_visit--; \
CELL *ptd0 = to_visit->ptd0; \
*ptd0 = to_visit->d0; \
} \
pop_text_stack(lvl); \
clean_tr(TR0 PASS_REGS); \
HR = InitialH; \
LOCAL_Error_TYPE = RESOURCE_ERROR_STACK; \
LOCAL_Error_Size = (ASP - HR) * sizeof(CELL); \
return false; \
2019-01-30 15:24:06 +00:00
}
2019-02-04 01:08:18 +00:00
#define CYC_LIST \
2019-02-06 15:08:25 +00:00
if (d0 == TermFreeTerm) { \
2019-02-08 09:33:07 +00:00
/*fprintf(stderr,"+%ld at %s\n", to_visit-to_visit0, __FUNCTION__);*/ \
2019-02-06 15:08:25 +00:00
while (to_visit > to_visit0) { \
2019-02-04 01:08:18 +00:00
to_visit--; \
2019-02-06 15:08:25 +00:00
to_visit->ptd0[0] = \
to_visit->d0; \
2019-02-04 01:08:18 +00:00
} \
2019-02-08 09:33:07 +00:00
pop_text_stack(lvl); /*fprintf(stderr,"<%ld at %s\n", to_visit-to_visit0, __FUNCTION__);*/ \
2019-02-04 01:08:18 +00:00
return true; \
}
#define CYC_APPL \
2019-02-06 15:08:25 +00:00
if (IsAtomTerm((CELL)f)) { \
2019-02-04 01:08:18 +00:00
while (to_visit > to_visit0) { \
2019-02-06 15:08:25 +00:00
to_visit--; \
to_visit->ptd0[0] = \
to_visit->d0; \
} \
2019-02-08 09:33:07 +00:00
/*fprintf(stderr,"<%ld at %s\n", to_visit-to_visit0, __FUNCTION__);*/ \
2019-02-06 15:08:25 +00:00
return true; \
2019-02-04 01:08:18 +00:00
}
/**
@brief routine to locate all variables in a term, and its applications */
static Term cyclic_complex_term(register CELL *pt0,
register CELL *pt0_end USES_REGS) {
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack(); \
2019-02-04 01:08:18 +00:00
WALK_COMPLEX_TERM__(CYC_LIST, CYC_APPL, {});
/* leave an empty slot to fill in later */
END_WALK();
return false;
def_aux_overflow();
}
bool Yap_IsCyclicTerm(Term t USES_REGS) {
if (IsVarTerm(t)) {
return false;
} else if (IsPrimitiveTerm(t)) {
return false;
} else {
return cyclic_complex_term(&(t)-1, &(t)PASS_REGS);
}
}
/** @pred cyclic_term( + _T_ )
Succeeds if the graph representation of the term has loops. Say,
the representation of a term `X` that obeys the equation `X=[X]`
term has a loop from the list to its head.
*/
static Int cyclic_term(USES_REGS1) /* cyclic_term(+T) */
{
return Yap_IsCyclicTerm(Deref(ARG1));
}
/**
@brief routine to locate all variables in a term, and its applications */
static bool ground_complex_term(register CELL *pt0,
register CELL *pt0_end USES_REGS) {
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack(); \
2019-02-04 01:08:18 +00:00
WALK_COMPLEX_TERM();
/* leave an empty slot to fill in later */
while (to_visit > to_visit0) {
to_visit--;
CELL *ptd0 = to_visit->ptd0;
*ptd0 = to_visit->d0;
}
pop_text_stack(lvl);
return false;
END_WALK();
/* Do we still have compound terms to visit */
pop_text_stack(lvl);
return true;
def_aux_overflow();
}
bool Yap_IsGroundTerm(Term t) {
CACHE_REGS
if (IsVarTerm(t)) {
return false;
} else if (IsPrimitiveTerm(t)) {
return true;
} else {
return ground_complex_term(&(t)-1, &(t)PASS_REGS);
}
}
/** @pred ground( _T_) is iso
Succeeds if there are no free variables in the term _T_.
*/
static Int ground(USES_REGS1) /* ground(+T) */
{
return Yap_IsGroundTerm(Deref(ARG1));
}
2019-02-01 13:14:33 +00:00
static Int var_in_complex_term(register CELL *pt0, register CELL *pt0_end,
Term v USES_REGS) {
2019-01-30 15:24:06 +00:00
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack(); \
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
2019-01-30 15:24:06 +00:00
2019-02-06 15:08:25 +00:00
if ((CELL)ptd0 == v) { /* we found it */
2019-02-01 13:14:33 +00:00
/* Do we still have compound terms to visit */
while (to_visit > to_visit0) {
to_visit--;
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
CELL *ptd0 = to_visit->ptd0;
*ptd0 = to_visit->d0;
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
pop_text_stack(lvl);
return true;
2019-01-30 15:24:06 +00:00
}
2019-02-05 10:31:17 +00:00
goto restart;
2019-02-01 13:14:33 +00:00
END_WALK();
if (to_visit > to_visit0) {
to_visit--;
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
CELL *ptd0 = to_visit->ptd0;
*ptd0 = to_visit->d0;
pt0 = to_visit->pt0;
pt0_end = to_visit->pt0_end;
}
2019-01-30 15:24:06 +00:00
pop_text_stack(lvl);
2019-02-01 13:14:33 +00:00
return false;
2019-01-30 15:24:06 +00:00
def_aux_overflow();
}
2019-02-01 13:14:33 +00:00
static Int var_in_term(Term v,
Term t USES_REGS) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
2019-02-01 13:14:33 +00:00
must_be_variable(v);
t = Deref(t);
2019-01-30 15:24:06 +00:00
if (IsVarTerm(t)) {
2019-02-01 13:14:33 +00:00
return (v == t);
2019-01-30 15:24:06 +00:00
} else if (IsPrimitiveTerm(t)) {
2019-02-01 13:14:33 +00:00
return (false);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
return (var_in_complex_term(&(t)-1, &(t), v PASS_REGS));
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
/** @pred variable_in_term(? _Term_,? _Var_)
Succeed if the second argument _Var_ is a variable and occurs in
term _Term_.
*/
static Int variable_in_term(USES_REGS1) {
return var_in_term(Deref(ARG2), Deref(ARG1) PASS_REGS);
2019-01-30 15:24:06 +00:00
}
/**
2019-02-04 01:08:18 +00:00
* @brief routine to locate all variables in a term, and its applications.
*/
2019-02-01 13:14:33 +00:00
static Term vars_in_complex_term(register CELL *pt0, register CELL *pt0_end,
Term inp USES_REGS) {
2019-01-30 15:24:06 +00:00
register tr_fr_ptr TR0 = TR;
CELL *InitialH = HR;
CELL output = AbsPair(HR);
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
push_text_stack(); \
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
/* do or pt2 are unbound */
*ptd0 = TermNil;
/* leave an empty slot to fill in later */
if (HR + 1024 > ASP) {
goto global_overflow;
}
HR[1] = AbsPair(HR + 2);
HR += 2;
HR[-2] = (CELL)ptd0;
/* next make sure noone will see this as a variable again */
if (TR > (tr_fr_ptr)LOCAL_TrailTop - 256) {
/* Trail overflow */
if (!Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true)) {
goto trail_overflow;
2019-01-30 15:24:06 +00:00
}
}
2019-02-01 13:14:33 +00:00
TrailTerm(TR++) = (CELL)ptd0;
2019-01-30 15:24:06 +00:00
2019-02-06 15:08:25 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
pop_text_stack(lvl);
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
if (HR != InitialH) {
/* close the list */
Term t2 = Deref(inp);
if (IsVarTerm(t2)) {
2019-02-01 13:14:33 +00:00
RESET_VARIABLE(HR - 1);
Yap_unify((CELL)(HR - 1), inp);
2019-01-30 15:24:06 +00:00
} else {
2019-02-01 13:14:33 +00:00
HR[-1] = t2; /* don't need to trail */
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
return (output);
2019-01-30 15:24:06 +00:00
} else {
2019-02-01 13:14:33 +00:00
return (inp);
2019-01-30 15:24:06 +00:00
}
def_trail_overflow();
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
def_aux_overflow();
2019-02-01 13:14:33 +00:00
def_global_overflow();
2019-01-30 15:24:06 +00:00
}
2019-02-04 01:08:18 +00:00
/**
* @pred variables_in_term( +_T_, +_SetOfVariables_, +_ExtendedSetOfVariables_ )
*
* _SetOfVariables_ must be a list of unbound variables. If so,
* _ExtendedSetOfVariables_ will include all te variables in the union
* of `vars(_T_)` and _SetOfVariables_.
*/
static Int variables_in_term(USES_REGS1) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
Term out, inp;
int count;
2019-02-01 13:14:33 +00:00
restart:
2019-01-30 15:24:06 +00:00
count = 0;
inp = Deref(ARG2);
while (!IsVarTerm(inp) && IsPairTerm(inp)) {
Term t = HeadOfTerm(inp);
if (IsVarTerm(t)) {
CELL *ptr = VarOfTerm(t);
*ptr = TermFoundVar;
TrailTerm(TR++) = t;
count++;
if (TR > (tr_fr_ptr)LOCAL_TrailTop - 256) {
2019-02-01 13:14:33 +00:00
clean_tr(TR - count PASS_REGS);
if (!Yap_growtrail(count * sizeof(tr_fr_ptr *), false)) {
return false;
}
goto restart;
2019-01-30 15:24:06 +00:00
}
}
inp = TailOfTerm(inp);
}
do {
Term t = Deref(ARG1);
2019-02-01 13:14:33 +00:00
out = vars_in_complex_term(&(t)-1, &(t), ARG2 PASS_REGS);
2019-01-30 15:24:06 +00:00
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
clean_tr(TR - count PASS_REGS);
return Yap_unify(ARG3, out);
2019-01-30 15:24:06 +00:00
}
/** @pred term_variables(? _Term_, - _Variables_, +_ExternalVars_) is iso
Unify the difference list between _Variables_ and _ExternaVars_
with the list of all variables of term _Term_. The variables
occur in the order of their first appearance when traversing the
term depth-first, left-to-right.
*/
2019-02-01 13:14:33 +00:00
static Int p_term_variables3(USES_REGS1) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
Term out;
do {
Term t = Deref(ARG1);
if (IsVarTerm(t)) {
Term out = Yap_MkNewPairTerm();
2019-02-01 13:14:33 +00:00
return Yap_unify(t, HeadOfTerm(out)) &&
Yap_unify(ARG3, TailOfTerm(out)) && Yap_unify(out, ARG2);
} else if (IsPrimitiveTerm(t)) {
2019-01-30 15:24:06 +00:00
return Yap_unify(ARG2, ARG3);
} else {
2019-02-01 13:14:33 +00:00
out = vars_in_complex_term(&(t)-1, &(t), ARG3 PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG2, out);
2019-01-30 15:24:06 +00:00
}
/**
* Exports a nil-terminated list with all the variables in a term.
* @param[t] the term
2019-02-01 13:14:33 +00:00
* @param[arity] the arity of the calling predicate (required for exact garbage
* collection).
2019-01-30 15:24:06 +00:00
* @param[USES_REGS] threading
*/
2019-02-01 13:14:33 +00:00
Term Yap_TermVariables(
Term t, UInt arity USES_REGS) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
Term out;
do {
t = Deref(t);
if (IsVarTerm(t)) {
return MkPairTerm(t, TermNil);
} else if (IsPrimitiveTerm(t)) {
return TermNil;
} else {
2019-02-01 13:14:33 +00:00
out = vars_in_complex_term(&(t)-1, &(t), TermNil PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(arity PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
return out;
}
/** @pred term_variables(? _Term_, - _Variables_) is iso
Unify _Variables_ with the list of all variables of term
_Term_. The variables occur in the order of their first
appearance when traversing the term depth-first, left-to-right.
*/
2019-02-01 13:14:33 +00:00
static Int p_term_variables(USES_REGS1) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
Term out;
if (!Yap_IsListOrPartialListTerm(ARG2)) {
2019-02-01 13:14:33 +00:00
Yap_Error(TYPE_ERROR_LIST, ARG2, "term_variables/2");
return false;
2019-01-30 15:24:06 +00:00
}
do {
Term t = Deref(ARG1);
2019-02-01 13:14:33 +00:00
out = vars_in_complex_term(&(t)-1, &(t), TermNil PASS_REGS);
2019-01-30 15:24:06 +00:00
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG2, out);
2019-01-30 15:24:06 +00:00
}
/** routine to locate attributed variables */
typedef struct att_rec {
CELL *beg, *end;
CELL oval;
} att_rec_t;
2019-02-01 13:14:33 +00:00
static Term attvars_in_complex_term(register CELL *pt0, register CELL *pt0_end,
Term inp USES_REGS) {
2019-01-30 15:24:06 +00:00
register tr_fr_ptr TR0 = TR;
CELL *InitialH = HR;
2019-02-04 15:10:06 +00:00
CELL output = inp;
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack(); \
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
if (IsAttVar(ptd0)) {
/* do or pt2 are unbound */
attvar_record *a0 = RepAttVar(ptd0);
if (a0->AttFunc == (Functor)TermNil)
goto restart;
/* leave an empty slot to fill in later */
if (HR + 1024 > ASP) {
goto global_overflow;
}
2019-02-04 15:10:06 +00:00
output = MkPairTerm( (CELL) & (a0->Done), output);
2019-02-01 13:14:33 +00:00
/* store the terms to visit */
if (to_visit + 32 >= to_visit_max) {
goto aux_overflow;
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
ptd0 = (CELL *)a0;
to_visit->pt0 = pt0;
to_visit->pt0_end = pt0_end;
to_visit->d0 = *ptd0;
to_visit->ptd0 = ptd0;
to_visit++;
*ptd0 = TermNil;
pt0_end = &RepAttVar(ptd0)->Atts;
pt0 = pt0_end - 1;
2019-01-30 15:24:06 +00:00
}
2019-02-06 15:08:25 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
pop_text_stack(lvl);
if (HR != InitialH) {
/* close the list */
Term t2 = Deref(inp);
if (IsVarTerm(t2)) {
2019-02-01 13:14:33 +00:00
RESET_VARIABLE(HR - 1);
Yap_unify((CELL)(HR - 1), t2);
2019-01-30 15:24:06 +00:00
} else {
2019-02-01 13:14:33 +00:00
HR[-1] = t2; /* don't need to trail */
2019-01-30 15:24:06 +00:00
}
2019-02-04 15:10:06 +00:00
2019-01-30 15:24:06 +00:00
}
2019-02-08 09:33:07 +00:00
/*fprintf(stderr,"<%ld at %s\n", to_visit-to_visit0, __FUNCTION__)*/;
2019-02-06 15:08:25 +00:00
return (output);
2019-01-30 15:24:06 +00:00
def_aux_overflow();
def_global_overflow();
}
2019-02-01 13:14:33 +00:00
/** @pred term_attvars(+ _Term_,- _AttVars_)
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
_AttVars_ is a list of all attributed variables in _Term_ and
its attributes. I.e., term_attvars/2 works recursively through
attributes. This predicate is Cycle-safe.
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
*/
static Int p_term_attvars(USES_REGS1) /* variables in term t */
2019-01-30 15:24:06 +00:00
{
Term out;
do {
Term t = Deref(ARG1);
if (IsPrimitiveTerm(t)) {
return Yap_unify(TermNil, ARG2);
} else {
2019-02-01 13:14:33 +00:00
out = attvars_in_complex_term(&(t)-1, &(t), TermNil PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
}
2019-01-30 15:24:06 +00:00
} while (out == 0L);
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG2, out);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
/** @brief output the difference between variables in _T_ and variables in some
* list.
2019-01-30 15:24:06 +00:00
*/
2019-02-01 13:14:33 +00:00
static Term new_vars_in_complex_term(register CELL *pt0, register CELL *pt0_end,
Term inp USES_REGS) {
2019-01-30 15:24:06 +00:00
register tr_fr_ptr TR0 = TR;
CELL *InitialH = HR;
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack(); \
2019-02-05 10:31:17 +00:00
HB=ASP;
CELL output = TermNil;
2019-02-03 21:35:12 +00:00
{
2019-02-04 01:08:18 +00:00
while (!IsVarTerm(inp) && IsPairTerm(inp)) {
Term t = HeadOfTerm(inp);
if (IsVarTerm(t)) {
2019-02-05 10:31:17 +00:00
YapBind( VarOfTerm(t), TermFoundVar );
2019-02-04 01:08:18 +00:00
if ((tr_fr_ptr)LOCAL_TrailTop - TR < 1024) {
2019-02-06 15:08:25 +00:00
2019-02-04 01:08:18 +00:00
if (!Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true)) {
goto trail_overflow;
}
2019-02-05 10:31:17 +00:00
pop_text_stack( lvl );
2019-02-01 13:14:33 +00:00
}
2019-01-30 15:24:06 +00:00
}
2019-02-04 01:08:18 +00:00
inp = TailOfTerm(inp);
2019-01-30 15:24:06 +00:00
}
}
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
2019-02-05 10:31:17 +00:00
output = MkPairTerm((CELL)ptd0,output);
YapBind( ptd0, TermFoundVar );
if ((tr_fr_ptr)LOCAL_TrailTop - TR < 1024) {
if (!Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true)) {
goto trail_overflow;
}
}
2019-02-01 13:14:33 +00:00
/* leave an empty slot to fill in later */
if (HR + 1024 > ASP) {
goto global_overflow;
}
END_WALK();
2019-02-06 15:08:25 +00:00
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
pop_text_stack(lvl);
2019-02-05 10:31:17 +00:00
HB = B->cp_h;
return output;
2019-01-30 15:24:06 +00:00
def_aux_overflow();
2019-02-01 13:14:33 +00:00
def_trail_overflow();
2019-01-30 15:24:06 +00:00
def_global_overflow();
}
/** @pred new_variables_in_term(+_CurrentVariables_, ? _Term_, -_Variables_)
Unify _Variables_ with the list of all variables of term
2019-02-01 13:14:33 +00:00
_Term_ that do not occur in _CurrentVariables_. The variables occur in the
order of their first appearance when traversing the term depth-first,
left-to-right.
2019-01-30 15:24:06 +00:00
*/
static Int
2019-02-01 13:14:33 +00:00
p_new_variables_in_term(USES_REGS1) /* variables within term t */
2019-01-30 15:24:06 +00:00
{
Term out;
do {
Term t = Deref(ARG2);
2019-02-01 13:14:33 +00:00
if (IsPrimitiveTerm(t))
2019-01-30 15:24:06 +00:00
out = TermNil;
2019-02-01 13:14:33 +00:00
else {
out = new_vars_in_complex_term(&(t)-1, &(t), Deref(ARG1) PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG3, out);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
#define FOUND_VAR() \
if (d0 == TermFoundVar) { \
/* leave an empty slot to fill in later */ \
if (HR + 1024 > ASP) { \
goto global_overflow; \
} \
HR[1] = AbsPair(HR + 2); \
HR += 2; \
HR[-2] = (CELL)ptd0; \
*ptd0 = TermNil; \
}
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
static Term vars_within_complex_term(register CELL *pt0, register CELL *pt0_end,
Term inp USES_REGS) {
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
tr_fr_ptr TR0 = TR;
2019-01-30 15:24:06 +00:00
CELL *InitialH = HR;
CELL output = AbsPair(HR);
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-01-30 15:24:06 +00:00
while (!IsVarTerm(inp) && IsPairTerm(inp)) {
Term t = HeadOfTerm(inp);
if (IsVarTerm(t)) {
CELL *ptr = VarOfTerm(t);
*ptr = TermFoundVar;
TrailTerm(TR++) = t;
if (TR > (tr_fr_ptr)LOCAL_TrailTop - 256) {
2019-02-01 13:14:33 +00:00
Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true);
2019-01-30 15:24:06 +00:00
}
}
inp = TailOfTerm(inp);
}
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM__({}, {}, FOUND_VAR());
2019-02-05 10:31:17 +00:00
goto restart;
2019-02-01 13:14:33 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
pop_text_stack(lvl);
if (HR != InitialH) {
HR[-1] = TermNil;
return output;
} else {
return TermNil;
}
def_aux_overflow();
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
def_global_overflow();
}
/** @pred variables_within_term(+_CurrentVariables_, ? _Term_, -_Variables_)
2019-02-01 13:14:33 +00:00
Unify _Variables_ with the list of all variables of term _Term_
that *also* occur in _CurrentVariables_. The variables occur in
the order of their first appearance when traversing the term
depth-first, left-to-right.
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
This predicate performs the opposite of new_variables_in_term/3.
2019-01-30 15:24:06 +00:00
*/
2019-02-01 13:14:33 +00:00
static Int p_variables_within_term(USES_REGS1) /* variables within term t */
2019-01-30 15:24:06 +00:00
{
Term out;
do {
Term t = Deref(ARG2);
2019-02-01 13:14:33 +00:00
if (IsPrimitiveTerm(t))
2019-01-30 15:24:06 +00:00
out = TermNil;
2019-02-01 13:14:33 +00:00
else {
out = vars_within_complex_term(&(t)-1, &(t), Deref(ARG1) PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG3, out);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
static Term free_vars_in_complex_term(CELL *pt0, CELL *pt0_end,
tr_fr_ptr TR0 USES_REGS) {
2019-01-30 15:24:06 +00:00
Term o = TermNil;
CELL *InitialH = HR;
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
/* do or pt2 are unbound */
*ptd0 = TermNil;
/* leave an empty slot to fill in later */
if (HR + 1024 > ASP) {
o = TermNil;
goto global_overflow;
}
HR[0] = (CELL)ptd0;
HR[1] = o;
o = AbsPair(HR);
HR += 2;
/* next make sure noone will see this as a variable again */
if (TR > (tr_fr_ptr)LOCAL_TrailTop - 256) {
/* Trail overflow */
if (!Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true)) {
goto trail_overflow;
2019-01-30 15:24:06 +00:00
}
}
2019-02-01 13:14:33 +00:00
TrailTerm(TR++) = (CELL)ptd0;
END_WALK();
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
pop_text_stack(lvl);
return o;
def_aux_overflow();
2019-02-01 13:14:33 +00:00
def_trail_overflow();
def_global_overflow();
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
static Term bind_vars_in_complex_term(CELL *pt0, CELL *pt0_end,
tr_fr_ptr TR0 USES_REGS) {
2019-01-30 15:24:06 +00:00
CELL *InitialH = HR;
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM();
/* do or pt2 are unbound */
*ptd0 = TermFoundVar;
/* next make sure noone will see this as a variable again */
if (TR > (tr_fr_ptr)LOCAL_TrailTop - 256) {
/* Trail overflow */
if (!Yap_growtrail((TR - TR0) * sizeof(tr_fr_ptr *), true)) {
2019-02-04 01:08:18 +00:00
while (to_visit > to_visit0) {
2019-02-03 21:35:12 +00:00
to_visit--;
CELL *ptd0 = to_visit->ptd0;
*ptd0 = to_visit->d0;
}
2019-02-01 13:14:33 +00:00
goto trail_overflow;
2019-01-30 15:24:06 +00:00
}
}
2019-02-01 13:14:33 +00:00
TrailTerm(TR++) = (CELL)ptd0;
2019-02-06 15:08:25 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
pop_text_stack(lvl);
2019-01-30 15:24:06 +00:00
return TermNil;
2019-02-01 13:14:33 +00:00
def_aux_overflow();
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
def_trail_overflow();
2019-01-30 15:24:06 +00:00
}
static Int
2019-02-01 13:14:33 +00:00
p_free_variables_in_term(USES_REGS1) /* variables within term t */
2019-01-30 15:24:06 +00:00
{
Term out;
Term t, t0;
Term found_module = 0L;
do {
tr_fr_ptr TR0 = TR;
t = t0 = Deref(ARG1);
while (!IsVarTerm(t) && IsApplTerm(t)) {
Functor f = FunctorOfTerm(t);
if (f == FunctorHat) {
2019-02-01 13:14:33 +00:00
out = bind_vars_in_complex_term(RepAppl(t), RepAppl(t) + 1,
TR0 PASS_REGS);
if (out == 0L) {
goto trail_overflow;
}
2019-01-30 15:24:06 +00:00
} else if (f == FunctorModule) {
2019-02-01 13:14:33 +00:00
found_module = ArgOfTerm(1, t);
2019-01-30 15:24:06 +00:00
} else if (f == FunctorCall) {
2019-02-01 13:14:33 +00:00
t = ArgOfTerm(1, t);
2019-01-30 15:24:06 +00:00
} else if (f == FunctorExecuteInMod) {
2019-02-01 13:14:33 +00:00
found_module = ArgOfTerm(2, t);
t = ArgOfTerm(1, t);
2019-01-30 15:24:06 +00:00
} else {
2019-02-01 13:14:33 +00:00
break;
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
t = ArgOfTerm(2, t);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
if (IsPrimitiveTerm(t))
2019-01-30 15:24:06 +00:00
out = TermNil;
else {
2019-02-01 13:14:33 +00:00
out = free_vars_in_complex_term(&(t)-1, &(t), TR0 PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out == 0L) {
trail_overflow:
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
}
} while (out == 0L);
2019-02-01 13:14:33 +00:00
if (found_module && t != t0) {
2019-01-30 15:24:06 +00:00
Term ts[2];
ts[0] = found_module;
ts[1] = t;
t = Yap_MkApplTerm(FunctorModule, 2, ts);
}
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG2, t) && Yap_unify(ARG3, out);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
#define FOUND_VAR_AGAIN() \
if (d0 == TermFoundVar) { \
CELL *pt2 = pt0; \
while (IsVarTerm(*pt2)) \
pt2 = (CELL *)(*pt2); \
HR[1] = AbsPair(HR + 2); \
HR[0] = (CELL)pt2; \
HR += 2; \
*pt2 = TermRefoundVar; \
}
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
static Term non_singletons_in_complex_term(CELL *pt0, CELL *pt0_end USES_REGS) {
tr_fr_ptr TR0 = TR;
2019-01-30 15:24:06 +00:00
CELL *InitialH = HR;
2019-02-04 22:10:30 +00:00
HB = (CELL *)ASP;
2019-01-30 15:24:06 +00:00
CELL output = AbsPair(HR);
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM__({}, {}, FOUND_VAR_AGAIN());
/* do or pt2 are unbound */
2019-02-04 22:10:30 +00:00
YapBind(ptd0,TermFoundVar);
2019-02-05 10:31:17 +00:00
goto restart;
2019-02-01 13:14:33 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
clean_tr(TR0 PASS_REGS);
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
pop_text_stack(lvl);
2019-02-04 22:10:30 +00:00
HB = (CELL*)B->cp_b;
2019-01-30 15:24:06 +00:00
if (HR != InitialH) {
/* close the list */
HR[-1] = Deref(ARG2);
return output;
} else {
return ARG2;
}
def_aux_overflow();
}
2019-02-01 13:14:33 +00:00
static Int p_non_singletons_in_term(
USES_REGS1) /* non_singletons in term t */
2019-01-30 15:24:06 +00:00
{
Term t;
Term out;
2019-02-01 13:14:33 +00:00
while (true) {
2019-01-30 15:24:06 +00:00
t = Deref(ARG1);
if (IsVarTerm(t)) {
out = ARG2;
2019-02-01 13:14:33 +00:00
} else if (IsPrimitiveTerm(t)) {
2019-01-30 15:24:06 +00:00
out = ARG2;
} else {
2019-02-01 13:14:33 +00:00
out = non_singletons_in_complex_term(&(t)-1, &(t)PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out != 0L) {
2019-02-01 13:14:33 +00:00
return Yap_unify(ARG3, out);
2019-01-30 15:24:06 +00:00
}
}
}
2019-02-01 13:14:33 +00:00
static Term numbervar(Int id USES_REGS) {
2019-01-30 15:24:06 +00:00
Term ts[1];
ts[0] = MkIntegerTerm(id);
return Yap_MkApplTerm(FunctorDollarVar, 1, ts);
}
2019-02-01 13:14:33 +00:00
static Term numbervar_singleton(USES_REGS1) {
2019-01-30 15:24:06 +00:00
Term ts[1];
ts[0] = MkIntegerTerm(-1);
return Yap_MkApplTerm(FunctorDollarVar, 1, ts);
}
2019-02-01 13:14:33 +00:00
static void renumbervar(Term t, Int id USES_REGS) {
2019-01-30 15:24:06 +00:00
Term *ts = RepAppl(t);
ts[1] = MkIntegerTerm(id);
}
2019-02-01 13:14:33 +00:00
#define RENUMBER_SINGLES \
2019-02-04 22:10:30 +00:00
if (singles ) { \
2019-02-01 13:14:33 +00:00
renumbervar(d0, numbv++ PASS_REGS); \
2019-02-04 01:08:18 +00:00
goto restart; \
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
static Int numbervars_in_complex_term(CELL *pt0, CELL *pt0_end, Int numbv,
int singles USES_REGS) {
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
tr_fr_ptr TR0 = TR;
2019-01-30 15:24:06 +00:00
CELL *InitialH = HR;
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-02-05 10:31:17 +00:00
WALK_COMPLEX_TERM__({}, {}, {});
2019-01-30 15:24:06 +00:00
2019-02-04 22:10:30 +00:00
if (IsAttVar(pt0))
continue;
2019-02-01 13:14:33 +00:00
/* do or pt2 are unbound */
2019-02-05 10:31:17 +00:00
if (singles || 0)
2019-02-04 22:10:30 +00:00
d0 = numbervar_singleton(PASS_REGS1);
2019-02-01 13:14:33 +00:00
else
2019-02-04 22:10:30 +00:00
d0 = numbervar(numbv++ PASS_REGS);
2019-02-01 13:14:33 +00:00
/* leave an empty slot to fill in later */
if (HR + 1024 > ASP) {
goto global_overflow;
}
/* next make sure noone will see this as a variable again */
2019-02-04 22:10:30 +00:00
YapBind(ptd0, d0);
2019-02-01 13:14:33 +00:00
END_WALK();
2019-01-30 15:24:06 +00:00
pop_text_stack(lvl);
return numbv;
def_aux_overflow();
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
def_global_overflow();
2019-02-05 10:31:17 +00:00
2019-02-01 13:14:33 +00:00
}
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
Int Yap_NumberVars(Term inp, Int numbv,
bool handle_singles) /*
* numbervariables in term t */
2019-01-30 15:24:06 +00:00
{
CACHE_REGS
2019-02-01 13:14:33 +00:00
Int out;
2019-01-30 15:24:06 +00:00
Term t;
2019-02-01 13:14:33 +00:00
restart:
2019-01-30 15:24:06 +00:00
t = Deref(inp);
2019-02-01 13:14:33 +00:00
if (IsPrimitiveTerm(t)) {
2019-01-30 15:24:06 +00:00
return numbv;
} else {
2019-02-01 13:14:33 +00:00
out = numbervars_in_complex_term(&(t)-1, &(t), numbv,
handle_singles PASS_REGS);
2019-01-30 15:24:06 +00:00
}
if (out < numbv) {
2019-02-01 13:14:33 +00:00
if (!expand_vts(3 PASS_REGS))
return false;
2019-01-30 15:24:06 +00:00
goto restart;
}
2019-02-01 13:14:33 +00:00
return out;
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
/** @pred numbervars( _T_,+ _N1_,- _Nn_)
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
Instantiates each variable in term _T_ to a term of the form:
`$VAR( _I_)`, with _I_ increasing from _N1_ to _Nn_.
2019-01-30 15:24:06 +00:00
2019-02-01 13:14:33 +00:00
*/
static Int p_numbervars(USES_REGS1) {
2019-01-30 15:24:06 +00:00
Term t2 = Deref(ARG2);
Int out;
if (IsVarTerm(t2)) {
2019-02-01 13:14:33 +00:00
Yap_Error(INSTANTIATION_ERROR, t2, "numbervars/3");
return false;
2019-01-30 15:24:06 +00:00
}
if (!IsIntegerTerm(t2)) {
2019-02-01 13:14:33 +00:00
Yap_Error(TYPE_ERROR_INTEGER, t2, "numbervars/3");
return (false);
2019-01-30 15:24:06 +00:00
}
2019-02-01 13:14:33 +00:00
if ((out = Yap_NumberVars(ARG1, IntegerOfTerm(t2), false)) < 0)
return false;
2019-01-30 15:24:06 +00:00
return Yap_unify(ARG3, MkIntegerTerm(out));
}
2019-02-01 13:14:33 +00:00
#define MAX_NUMBERED \
if (FunctorOfTerm(d0) == FunctorDollarVar) { \
Term t1 = ArgOfTerm(1, d0); \
Int i; \
if (IsIntegerTerm(t1) && ((i = IntegerOfTerm(t1)) > *maxp)) \
*maxp = i; \
2019-02-04 01:08:18 +00:00
goto restart; \
2019-01-31 16:40:41 +00:00
}
2019-02-01 13:14:33 +00:00
static int max_numbered_var(CELL *pt0, CELL *pt0_end, Int *maxp USES_REGS) {
2019-02-06 15:08:25 +00:00
int lvl = push_text_stack();
2019-02-01 13:14:33 +00:00
WALK_COMPLEX_TERM__({}, MAX_NUMBERED, {});
END_WALK();
2019-01-31 16:40:41 +00:00
/* Do we still have compound terms to visit */
if (to_visit > to_visit0) {
to_visit--;
pt0 = to_visit->pt0;
pt0_end = to_visit->pt0_end;
CELL *ptd0 = to_visit->ptd0;
*ptd0 = to_visit->d0;
}
prune(B PASS_REGS);
pop_text_stack(lvl);
return 0;
def_aux_overflow();
2019-02-01 13:14:33 +00:00
}
2019-01-31 16:40:41 +00:00
2019-02-02 22:33:18 +00:00
static Int MaxNumberedVar(Term inp, UInt arity PASS_REGS) {
2019-01-31 16:40:41 +00:00
Term t = Deref(inp);
if (IsPrimitiveTerm(t)) {
return MkIntegerTerm(0);
} else {
Int res;
Int max;
2019-02-01 13:14:33 +00:00
res = max_numbered_var(&t - 1, &t, &max PASS_REGS) - 1;
if (res < 0)
return -1;
2019-01-31 16:40:41 +00:00
return MkIntegerTerm(max);
}
}
2019-02-02 22:33:18 +00:00
/**
* @pred largest_numbervar( +_Term_, -Max)
*
2019-02-04 01:08:18 +00:00
* Unify _Max_ with the largest integer _I_ such that `$VAR(I)` is a
2019-02-02 22:33:18 +00:00
* sub-term of _Term_.
*
* This built-in predicate is useful if part of a term has been grounded, and
* now you want to ground the full term.
*/
2019-02-04 01:08:18 +00:00
static Int largest_numbervar(USES_REGS1) {
2019-02-02 22:33:18 +00:00
return Yap_unify(MaxNumberedVar(Deref(ARG1), 2 PASS_REGS), ARG2);
}
2019-02-01 13:14:33 +00:00
2019-02-06 00:08:15 +00:00
static Term BREAK_LOOP(Int ddep) {
2019-02-08 09:33:07 +00:00
char buf[64];
snprintf(buf, 63, "@^[" Int_FORMAT "]", ddep);
return MkAtomTerm(Yap_LookupAtom(buf));
2019-02-02 22:33:18 +00:00
}
2019-02-04 15:10:06 +00:00
static Term UNFOLD_LOOP(Term t, Term *b) {
Term os[2], o;
os[0] = o = MkVarTerm();
os[1] = t;
Term ti = Yap_MkApplTerm(FunctorEq, 2, os);
*b = MkPairTerm(ti, *b);
2019-02-02 22:33:18 +00:00
return o;
}
2019-01-31 16:40:41 +00:00
2019-02-01 13:14:33 +00:00
2019-02-08 09:33:07 +00:00
typedef struct block_connector {
Int id; //> index in the array;
Term source; //> source;
CELL *copy; //> copy;
CELL header; //> backup of first word of the source data;
CELL reference; //> term used to refer the copy.
} cl_connector;
2019-02-02 22:33:18 +00:00
2019-02-08 09:33:07 +00:00
Int cp_link(Term t,Int i, Int j, cl_connector *q, Int max, CELL *tailp)
{
Term ref, h, *s, *ostart;
bool pair = false;
ssize_t n;
if (IsVarTerm(t) || IsPrimitiveTerm(t)) {
q[i].copy[j] = t;
return max;
}
ostart = HR;
if (IsPairTerm(t)) {
h = HeadOfTerm(t);
s = RepPair(t);
n = 2;
pair = true;
ref = AbsPair(ostart);
} else {
h = (CELL)FunctorOfTerm(t);
s = RepAppl(t);
n = ArityOfFunctor(FunctorOfTerm(t));
ref = AbsAppl(ostart);
*ostart++ = s[0];
}
if (HR > s && H0 < s) {
// first time, create a new term
q[max].id = max;
q[max].source = t;
q[max].copy = ostart;
q[max].header = s[0];
q[max].reference = ref;
s[0] = max*sizeof(CELL);
HR += n;
max++;
} else {
Int id = h/sizeof(CELL);
if (q[id].reference == ref) {
q[id].reference = UNFOLD_LOOP(t, tailp);
2019-02-06 15:08:25 +00:00
}
2019-02-08 09:33:07 +00:00
q[i].copy[j] = q[id].reference;
2019-02-02 22:33:18 +00:00
}
2019-02-08 09:33:07 +00:00
return max;
2019-02-01 13:14:33 +00:00
}
2019-02-08 09:33:07 +00:00
2019-02-06 00:08:15 +00:00
Term Yap_BreakCycles(Term inp, UInt arity, Term *listp USES_REGS) {
2019-02-02 22:33:18 +00:00
2019-02-08 09:33:07 +00:00
int lvl = push_text_stack();
Term t = Deref(inp);
ssize_t qsize = 2048, qlen=0;
cl_connector *q = Malloc(qsize * sizeof(cl_connector)), *q0 = q;
Term *s;
2019-02-02 22:33:18 +00:00
if (IsVarTerm(t) || IsPrimitiveTerm(t)) {
2019-02-01 13:14:33 +00:00
return t;
2019-02-08 09:33:07 +00:00
} else {
Int i=0;
qlen = cp_link(t, 0, 0, q, qlen, listp);
while (i < qlen) {
arity_t n, j;
if (IsPairTerm( q[i].source )) {
s = RepPair( q[i].source );
n = 2;
qlen = cp_link(q[i].header, i, 0, q, qlen, listp);
qlen = cp_link(s[1], i, 1, q, qlen, listp);
} else {
s = RepAppl( q[i].source )+1;
n = ArityOfFunctor((Functor)q[i].header);
for (j = 0; j<n; j++) {
qlen = cp_link(s[j], i, j, q, qlen, listp);
}
}
i++;
}
2019-02-01 13:14:33 +00:00
}
2019-02-08 09:33:07 +00:00
Int i;
for (i =0; i < qlen; i++) {
if (IsPairTerm(t)) {
RepPair(q[i].source)[0] = q[i].header;
} else {
RepAppl(q[i].source)[0] = q[i].header;
}
}
pop_text_stack(lvl);
2019-02-06 00:08:15 +00:00
2019-02-08 09:33:07 +00:00
return q[0].reference;
2019-02-01 13:14:33 +00:00
}
2019-02-04 01:08:18 +00:00
/** @pred rational_term_to_tree(? _TI_,- _TF_, ?SubTerms, ?MoreSubterms)
2019-02-02 22:33:18 +00:00
2019-02-04 01:08:18 +00:00
The term _TF_ is a forest representation (without cycles) for
the Prolog term _TI_. The term _TF_ is the main term. The
difference list _SubTerms_-_MoreSubterms_ stores terms of the
form _V=T_, where _V_ is a new variable occuring in _TF_, and
_T_ is a copy of a sub-term from _TI_.
2019-02-02 22:33:18 +00:00
2019-02-04 01:08:18 +00:00
*/
static Int p_break_rational(USES_REGS1) {
2019-02-08 09:33:07 +00:00
Term t = Deref(ARG1);
2019-02-06 00:08:15 +00:00
Term l = Deref(ARG4);
2019-02-04 01:08:18 +00:00
if (IsVarTerm(l))
Yap_unify(l, MkVarTerm());
2019-02-06 00:08:15 +00:00
return Yap_unify(Yap_BreakCycles(t, 4, &l PASS_REGS), ARG2) &&
Yap_unify(l, ARG3) ;
2019-02-02 22:33:18 +00:00
}
2019-02-01 13:14:33 +00:00
void Yap_InitTermCPreds(void) {
2019-02-02 22:33:18 +00:00
Yap_InitCPred("rational_term_to_tree", 4, p_break_rational, 0);
2019-01-30 15:24:06 +00:00
Yap_InitCPred("term_variables", 2, p_term_variables, 0);
Yap_InitCPred("term_variables", 3, p_term_variables3, 0);
2019-02-04 01:08:18 +00:00
Yap_InitCPred("$variables_in_term", 3, variables_in_term, 0);
2019-01-30 15:24:06 +00:00
Yap_InitCPred("$free_variables_in_term", 3, p_free_variables_in_term, 0);
Yap_InitCPred("term_attvars", 2, p_term_attvars, 0);
CurrentModule = TERMS_MODULE;
2019-02-01 13:14:33 +00:00
Yap_InitCPred("variable_in_term", 2, variable_in_term, 0);
2019-01-30 15:24:06 +00:00
Yap_InitCPred("variables_within_term", 3, p_variables_within_term, 0);
Yap_InitCPred("new_variables_in_term", 3, p_new_variables_in_term, 0);
CurrentModule = PROLOG_MODULE;
2019-02-01 13:14:33 +00:00
2019-01-30 15:24:06 +00:00
Yap_InitCPred("$non_singletons_in_term", 3, p_non_singletons_in_term, 0);
2019-02-04 01:08:18 +00:00
Yap_InitCPred("ground", 1, ground, SafePredFlag);
Yap_InitCPred("cyclic_term", 1, cyclic_term, SafePredFlag);
2019-01-30 15:24:06 +00:00
2019-02-05 10:31:17 +00:00
Yap_InitCPred("numbervars", 3, p_numbervars, 0);
2019-02-02 22:33:18 +00:00
Yap_InitCPred("largest_numbervar", 2, largest_numbervar, 0);
2019-01-30 15:24:06 +00:00
}