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/attvar.c

1050 lines
27 KiB
C
Raw Normal View History

2017-04-13 21:42:34 +01:00
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
2018-05-10 13:11:56 +01:00
* File: attvar.c * Last rev:
** mods: * comments: YAP support for attributed vars *
* *
*************************************************************************/
#ifdef SCCS
2015-11-06 18:22:31 +00:00
static char SccsId[] = "%W% %G%";
#endif
2018-05-01 23:25:58 +01:00
/**
* @file attvar.c
* @author VITOR SANTOS COSTA <vsc@VITORs-MBP-2.lan>
* @date Mon Apr 30 09:31:59 2018
2018-05-10 13:11:56 +01:00
*
2018-05-01 23:25:58 +01:00
* @brief attributed variables
* @namespace prolog
2018-05-10 13:11:56 +01:00
*
2018-05-01 23:25:58 +01:00
*/
#include "Yap.h"
#include "YapHeap.h"
2018-05-10 13:11:56 +01:00
#include "Yatom.h"
#include "attvar.h"
2018-05-10 13:11:56 +01:00
#include "heapgc.h"
#ifndef NULL
#define NULL (void *)0
#endif
2017-04-13 21:42:34 +01:00
/**
2018-05-10 13:11:56 +01:00
@defgroup AttributedVariables_Builtins Low-level support for Attributed
Variables
2017-05-02 07:42:21 +01:00
@brief Implementation of Attribute Declarations
2018-05-10 13:11:56 +01:00
@ingroup AttributedVariables
2017-05-02 07:42:21 +01:00
@{
2015-01-04 23:58:23 +00:00
*/
#ifdef COROUTINING
#define TermVoidAtt TermFoundVar
2015-11-06 18:22:31 +00:00
static CELL *AddToQueue(attvar_record *attv USES_REGS) {
Term t[2];
Term WGs, ng;
2015-11-06 18:22:31 +00:00
t[0] = (CELL) & (attv->Done);
t[1] = attv->Value;
/* follow the chain */
2011-05-04 10:11:41 +01:00
WGs = Yap_ReadTimedVar(LOCAL_WokenGoals);
ng = Yap_MkApplTerm(FunctorAttGoal, 2, t);
2011-05-04 10:11:41 +01:00
Yap_UpdateTimedVar(LOCAL_WokenGoals, MkPairTerm(ng, WGs));
if ((Term)WGs == TermNil) {
/* from now on, we have to start waking up goals */
Yap_signal(YAP_WAKEUP_SIGNAL);
}
2015-11-06 18:22:31 +00:00
return (RepAppl(ng) + 2);
}
2015-11-06 18:22:31 +00:00
static void AddFailToQueue(USES_REGS1) {
Term WGs;
/* follow the chain */
2011-05-04 10:11:41 +01:00
WGs = Yap_ReadTimedVar(LOCAL_WokenGoals);
2011-05-04 10:11:41 +01:00
Yap_UpdateTimedVar(LOCAL_WokenGoals, MkPairTerm(MkAtomTerm(AtomFail), WGs));
if ((Term)WGs == TermNil) {
/* from now on, we have to start waking up goals */
Yap_signal(YAP_WAKEUP_SIGNAL);
}
}
2015-11-06 18:22:31 +00:00
static attvar_record *BuildNewAttVar(USES_REGS1) {
attvar_record *newv;
/* add a new attributed variable */
2014-01-19 21:15:05 +00:00
newv = (attvar_record *)HR;
2015-11-06 18:22:31 +00:00
HR = (CELL *)(newv + 1);
newv->AttFunc = FunctorAttVar;
RESET_VARIABLE(&(newv->Value));
RESET_VARIABLE(&(newv->Done));
RESET_VARIABLE(&(newv->Atts));
return newv;
}
2015-11-06 18:22:31 +00:00
static int CopyAttVar(CELL *orig, struct cp_frame **to_visit_ptr,
CELL *res USES_REGS) {
register attvar_record *attv = RepAttVar(orig);
register attvar_record *newv;
struct cp_frame *to_visit = *to_visit_ptr;
CELL *vt;
2015-11-06 18:22:31 +00:00
if (!(newv = BuildNewAttVar(PASS_REGS1)))
return FALSE;
vt = &(attv->Atts);
2015-11-06 18:22:31 +00:00
to_visit->start_cp = vt - 1;
to_visit->end_cp = vt;
if (IsVarTerm(attv->Atts)) {
2014-01-19 21:15:05 +00:00
Bind_Global_NonAtt(&newv->Atts, (CELL)HR);
to_visit->to = HR;
HR++;
} else {
to_visit->to = &(newv->Atts);
}
to_visit->oldv = vt[-1];
to_visit->ground = FALSE;
2015-11-06 18:22:31 +00:00
*to_visit_ptr = to_visit + 1;
*res = (CELL) & (newv->Done);
return TRUE;
}
2015-11-06 18:22:31 +00:00
static Term AttVarToTerm(CELL *orig) {
attvar_record *attv = RepAttVar(orig);
return attv->Atts;
}
2015-11-06 18:22:31 +00:00
static int IsEmptyWakeUp(Term atts) {
2013-04-30 21:23:01 +01:00
Atom name = NameOfFunctor(FunctorOfTerm(atts));
Atom *pt = EmptyWakeups;
int i = 0;
while (i < MaxEmptyWakeups) {
2015-11-06 18:22:31 +00:00
if (pt[i++] == name)
return TRUE;
2013-04-30 21:23:01 +01:00
}
return FALSE;
}
2015-11-06 18:22:31 +00:00
void Yap_MkEmptyWakeUp(Atom mod) {
2013-04-30 21:23:01 +01:00
if (MaxEmptyWakeups == MAX_EMPTY_WAKEUPS)
2015-11-06 18:22:31 +00:00
Yap_Error(SYSTEM_ERROR_INTERNAL, TermNil,
"too many modules that do not wake up");
2013-04-30 21:23:01 +01:00
EmptyWakeups[MaxEmptyWakeups++] = mod;
}
2015-11-06 18:22:31 +00:00
static int TermToAttVar(Term attvar, Term to USES_REGS) {
attvar_record *attv = BuildNewAttVar(PASS_REGS1);
if (!attv)
return FALSE;
2011-03-18 19:34:58 +00:00
Bind_Global_NonAtt(&attv->Atts, attvar);
*VarOfTerm(to) = AbsAttVar(attv);
return TRUE;
}
2015-11-06 18:22:31 +00:00
static void WakeAttVar(CELL *pt1, CELL reg2 USES_REGS) {
/* if bound to someone else, follow until we find the last one */
attvar_record *attv = RepAttVar(pt1);
2014-01-19 21:15:05 +00:00
CELL *myH = HR;
CELL *bind_ptr;
if (IsVarTerm(Deref(attv->Atts))) {
/* no attributes to wake */
return;
}
if (IsVarTerm(reg2)) {
if (pt1 == VarOfTerm(reg2))
return;
if (IsAttachedTerm(reg2)) {
attvar_record *susp2 = RepAttVar(VarOfTerm(reg2));
/* binding two suspended variables, be careful */
if (susp2 >= attv) {
2015-11-06 18:22:31 +00:00
if (!IsVarTerm(susp2->Value) || !IsUnboundVar(&susp2->Value)) {
/* oops, our goal is on the queue to be woken */
if (!Yap_unify(susp2->Value, (CELL)pt1)) {
AddFailToQueue(PASS_REGS1);
}
}
Bind_Global_NonAtt(&(susp2->Value), (CELL)pt1);
AddToQueue(susp2 PASS_REGS);
return;
}
} else {
2011-03-18 19:34:58 +00:00
Bind_NonAtt(VarOfTerm(reg2), (CELL)pt1);
return;
}
}
2013-04-30 21:23:01 +01:00
if (IsEmptyWakeUp(attv->Atts)) {
Bind_Global_NonAtt(&(attv->Value), reg2);
Bind_Global_NonAtt(&(attv->Done), attv->Value);
return;
}
if (!IsVarTerm(attv->Value) || !IsUnboundVar(&attv->Value)) {
/* oops, our goal is on the queue to be woken */
if (!Yap_unify(attv->Value, reg2)) {
2018-08-15 01:29:20 +01:00
AddFailToQueue(PASS_REGS1);
}
return;
}
bind_ptr = AddToQueue(attv PASS_REGS);
if (IsNonVarTerm(reg2)) {
if (IsPairTerm(reg2) && RepPair(reg2) == myH)
2014-01-19 21:15:05 +00:00
reg2 = AbsPair(HR);
else if (IsApplTerm(reg2) && RepAppl(reg2) == myH)
2014-01-19 21:15:05 +00:00
reg2 = AbsAppl(HR);
}
*bind_ptr = reg2;
2011-03-18 19:34:58 +00:00
Bind_Global_NonAtt(&(attv->Value), reg2);
}
2015-11-06 18:22:31 +00:00
void Yap_WakeUp(CELL *pt0) {
CACHE_REGS
2018-05-10 13:11:56 +01:00
CELL d0 = *pt0;
RESET_VARIABLE(pt0);
WakeAttVar(pt0, d0 PASS_REGS);
}
2015-11-06 18:22:31 +00:00
static void mark_attvar(CELL *orig) { return; }
2015-11-06 18:22:31 +00:00
static Term BuildAttTerm(Functor mfun, UInt ar USES_REGS) {
2014-01-19 21:15:05 +00:00
CELL *h0 = HR;
UInt i;
2015-11-06 18:22:31 +00:00
if (HR + (1024 + ar) > ASP) {
LOCAL_Error_Size = ar * sizeof(CELL);
return 0L;
}
2014-01-19 21:15:05 +00:00
HR[0] = (CELL)mfun;
2015-11-06 18:22:31 +00:00
RESET_VARIABLE(HR + 1);
2014-01-19 21:15:05 +00:00
HR += 2;
2015-11-06 18:22:31 +00:00
for (i = 1; i < ar; i++) {
2014-01-19 21:15:05 +00:00
*HR = TermVoidAtt;
HR++;
}
return AbsAppl(h0);
}
2015-11-06 18:22:31 +00:00
static Term SearchAttsForModule(Term start, Functor mfun) {
do {
2015-11-06 18:22:31 +00:00
if (IsVarTerm(start) || FunctorOfTerm(start) == mfun)
return start;
2015-11-06 18:22:31 +00:00
start = ArgOfTerm(1, start);
} while (TRUE);
}
2015-11-06 18:22:31 +00:00
static Term SearchAttsForModuleName(Term start, Atom mname) {
do {
2015-11-06 18:22:31 +00:00
if (IsVarTerm(start) || NameOfFunctor(FunctorOfTerm(start)) == mname)
return start;
2015-11-06 18:22:31 +00:00
start = ArgOfTerm(1, start);
} while (TRUE);
}
2015-11-06 18:22:31 +00:00
static void AddNewModule(attvar_record *attv, Term t, int new,
int do_it USES_REGS) {
CELL *newp = RepAppl(t) + 2;
UInt i, ar = ArityOfFunctor((Functor)newp[-2]);
2015-11-06 18:22:31 +00:00
for (i = 1; i < ar; i++) {
Term n = Deref(*newp);
if (n == TermFreeTerm) {
*newp = TermVoidAtt;
} else {
if (n != TermVoidAtt)
2015-11-06 18:22:31 +00:00
do_it = TRUE;
}
newp++;
}
if (!do_it)
return;
2011-03-18 19:34:58 +00:00
if (new) {
attv->Atts = t;
} else if (IsVarTerm(attv->Atts)) {
2015-11-06 18:22:31 +00:00
MaBind(&(attv->Atts), t);
} else {
Term *wherep = &attv->Atts;
do {
if (IsVarTerm(*wherep)) {
2015-11-06 18:22:31 +00:00
Bind_Global_NonAtt(wherep, t);
return;
} else {
2015-11-06 18:22:31 +00:00
wherep = RepAppl(Deref(*wherep)) + 1;
}
} while (TRUE);
}
}
2015-11-06 18:22:31 +00:00
static void ReplaceAtts(attvar_record *attv, Term oatt, Term att USES_REGS) {
UInt ar = ArityOfFunctor(FunctorOfTerm(oatt)), i;
2015-11-06 18:22:31 +00:00
CELL *oldp = RepAppl(oatt) + 1;
CELL *newp;
if (oldp > HB) {
oldp++;
2015-11-06 18:22:31 +00:00
newp = RepAppl(att) + 2;
/* if deterministic */
2015-11-06 18:22:31 +00:00
for (i = 1; i < ar; i++) {
Term n = Deref(*newp);
if (n != TermFreeTerm) {
2015-11-06 18:22:31 +00:00
*oldp = n;
}
oldp++;
newp++;
}
return;
}
2015-11-06 18:22:31 +00:00
newp = RepAppl(att) + 1;
*newp++ = *oldp++;
2015-11-06 18:22:31 +00:00
for (i = 1; i < ar; i++) {
Term n = Deref(*newp);
if (n == TermFreeTerm) {
*newp = Deref(*oldp);
}
oldp++;
newp++;
}
if (attv->Atts == oatt) {
if (RepAppl(attv->Atts) >= HB)
attv->Atts = att;
else
MaBind(&(attv->Atts), att);
} else {
Term *wherep = &attv->Atts;
do {
if (*wherep == oatt) {
2015-11-06 18:22:31 +00:00
MaBind(wherep, att);
return;
} else {
2015-11-06 18:22:31 +00:00
wherep = RepAppl(Deref(*wherep)) + 1;
}
} while (TRUE);
}
}
2015-11-06 18:22:31 +00:00
static void DelAllAtts(attvar_record *attv USES_REGS) {
MaBind(&(attv->Done), attv->Value);
}
2015-11-06 18:22:31 +00:00
static void DelAtts(attvar_record *attv, Term oatt USES_REGS) {
Term t = ArgOfTerm(1, oatt);
if (attv->Atts == oatt) {
if (IsVarTerm(t)) {
DelAllAtts(attv PASS_REGS);
return;
}
if (RepAppl(attv->Atts) >= HB)
attv->Atts = t;
else
MaBind(&(attv->Atts), t);
} else {
Term *wherep = &attv->Atts;
do {
if (*wherep == oatt) {
2015-11-06 18:22:31 +00:00
MaBind(wherep, t);
return;
} else {
2015-11-06 18:22:31 +00:00
wherep = RepAppl(Deref(*wherep)) + 1;
}
} while (TRUE);
}
}
2015-11-06 18:22:31 +00:00
static void PutAtt(Int pos, Term atts, Term att USES_REGS) {
2014-01-19 21:15:05 +00:00
if (IsVarTerm(att) && VarOfTerm(att) > HR && VarOfTerm(att) < LCL0) {
/* globalise locals */
Term tnew = MkVarTerm();
2013-04-17 02:04:53 +01:00
Bind_NonAtt(VarOfTerm(att), tnew);
att = tnew;
}
2015-11-06 18:22:31 +00:00
MaBind(RepAppl(atts) + pos, att);
}
2015-11-06 18:22:31 +00:00
static Int BindAttVar(attvar_record *attv USES_REGS) {
if (IsVarTerm(attv->Done) && IsUnboundVar(&attv->Done)) {
/* make sure we are not trying to bind a variable against itself */
if (!IsVarTerm(attv->Value)) {
2011-03-18 19:34:58 +00:00
Bind_Global_NonAtt(&(attv->Done), attv->Value);
} else if (IsVarTerm(attv->Value)) {
Term t = Deref(attv->Value);
if (IsVarTerm(t)) {
2015-11-06 18:22:31 +00:00
if (IsAttachedTerm(t)) {
attvar_record *attv2 = RepAttVar(VarOfTerm(t));
if (attv2 < attv) {
Bind_Global_NonAtt(&(attv->Done), t);
} else {
Bind_Global_NonAtt(&(attv2->Done), AbsAttVar(attv));
}
} else {
Yap_Error(SYSTEM_ERROR_INTERNAL, (CELL) & (attv->Done),
"attvar was bound when unset");
return (FALSE);
}
} else {
2015-11-06 18:22:31 +00:00
Bind_Global_NonAtt(&(attv->Done), t);
}
}
2015-11-06 18:22:31 +00:00
return (TRUE);
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(SYSTEM_ERROR_INTERNAL, (CELL) & (attv->Done),
"attvar was bound when set");
return (FALSE);
}
}
2015-11-06 18:22:31 +00:00
static Int UnBindAttVar(attvar_record *attv) {
RESET_VARIABLE(&(attv->Value));
2015-11-06 18:22:31 +00:00
return (TRUE);
}
2015-11-06 18:22:31 +00:00
static Term GetAllAtts(attvar_record *attv) {
/* check if we are already there */
return attv->Atts;
}
2015-11-18 15:06:25 +00:00
static Int put_att(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
attvar_record *attv;
Atom modname = AtomOfTerm(Deref(ARG2));
UInt ar = IntegerOfTerm(Deref(ARG3));
Functor mfun;
Term tatts;
int new = FALSE;
if (IsAttachedTerm(inp)) {
attv = RepAttVar(VarOfTerm(inp));
} else {
2015-11-06 18:22:31 +00:00
while (!(attv = BuildNewAttVar(PASS_REGS1))) {
LOCAL_Error_Size = sizeof(attvar_record);
if (!Yap_gcl(LOCAL_Error_Size, 5, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
}
new = TRUE;
}
2015-11-06 18:22:31 +00:00
mfun = Yap_MkFunctor(modname, ar);
if (IsVarTerm(tatts = SearchAttsForModule(attv->Atts, mfun))) {
while (!(tatts = BuildAttTerm(mfun, ar PASS_REGS))) {
if (!Yap_gcl(LOCAL_Error_Size, 5, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
}
2012-08-14 22:07:26 +01:00
{
2015-11-06 18:22:31 +00:00
CELL *ptr = VarOfTerm(Deref(ARG1));
CELL d0 = AbsAttVar(attv);
Bind_NonAtt(ptr, d0);
2012-08-14 22:07:26 +01:00
}
AddNewModule(attv, tatts, new, TRUE PASS_REGS);
}
PutAtt(IntegerOfTerm(Deref(ARG4)), tatts, Deref(ARG5) PASS_REGS);
return TRUE;
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of put_attributes/2");
return FALSE;
}
}
2015-11-18 15:06:25 +00:00
static Int put_att_term(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
attvar_record *attv;
if (IsAttachedTerm(inp)) {
attv = RepAttVar(VarOfTerm(inp));
2011-03-18 19:34:58 +00:00
MaBind(&(attv->Atts), Deref(ARG2));
} else {
2015-11-06 18:22:31 +00:00
while (!(attv = BuildNewAttVar(PASS_REGS1))) {
LOCAL_Error_Size = sizeof(attvar_record);
if (!Yap_gcl(LOCAL_Error_Size, 5, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
inp = Deref(ARG1);
}
2011-03-18 19:34:58 +00:00
Bind_NonAtt(VarOfTerm(inp), AbsAttVar(attv));
attv->Atts = Deref(ARG2);
}
return TRUE;
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of put_att_term/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int rm_att(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
attvar_record *attv;
Atom modname = AtomOfTerm(Deref(ARG2));
UInt ar = IntegerOfTerm(Deref(ARG3));
Functor mfun;
Term tatts;
int new = FALSE;
if (IsAttachedTerm(inp)) {
attv = RepAttVar(VarOfTerm(inp));
} else {
2015-11-06 18:22:31 +00:00
while (!(attv = BuildNewAttVar(PASS_REGS1))) {
LOCAL_Error_Size = sizeof(attvar_record);
if (!Yap_gcl(LOCAL_Error_Size, 5, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
}
new = TRUE;
Yap_unify(ARG1, AbsAttVar(attv));
}
2015-11-06 18:22:31 +00:00
mfun = Yap_MkFunctor(modname, ar);
if (IsVarTerm(tatts = SearchAttsForModule(attv->Atts, mfun))) {
while (!(tatts = BuildAttTerm(mfun, ar PASS_REGS))) {
2015-11-06 18:22:31 +00:00
if (!Yap_gcl(LOCAL_Error_Size, 4, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
}
2015-11-06 18:22:31 +00:00
AddNewModule(attv, tatts, new, FALSE PASS_REGS);
} else {
PutAtt(IntegerOfTerm(Deref(ARG4)), tatts, TermVoidAtt PASS_REGS);
}
return TRUE;
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp, "first argument of rm_att/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int put_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
attvar_record *attv;
2010-03-30 12:45:32 +01:00
Term otatts;
Term tatts = Deref(ARG2);
Functor mfun = FunctorOfTerm(tatts);
int new = FALSE;
if (IsAttachedTerm(inp)) {
attv = RepAttVar(VarOfTerm(inp));
} else {
2015-11-06 18:22:31 +00:00
while (!(attv = BuildNewAttVar(PASS_REGS1))) {
LOCAL_Error_Size = sizeof(attvar_record);
if (!Yap_gcl(LOCAL_Error_Size, 2, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
}
new = TRUE;
Yap_unify(ARG1, AbsAttVar(attv));
}
2015-11-06 18:22:31 +00:00
/* we may have a stack shift meanwhile!! */
2010-03-30 12:45:32 +01:00
tatts = Deref(ARG2);
if (IsVarTerm(tatts)) {
2015-11-06 18:22:31 +00:00
Yap_Error(INSTANTIATION_ERROR, tatts, "second argument of put_att/2");
return FALSE;
} else if (!IsApplTerm(tatts)) {
2015-11-06 18:22:31 +00:00
Yap_Error(TYPE_ERROR_COMPOUND, tatts, "second argument of put_att/2");
return FALSE;
}
2015-11-06 18:22:31 +00:00
if (IsVarTerm(otatts = SearchAttsForModule(attv->Atts, mfun))) {
AddNewModule(attv, tatts, new, FALSE PASS_REGS);
} else {
ReplaceAtts(attv, otatts, tatts PASS_REGS);
}
return TRUE;
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of put_att/2");
return FALSE;
}
}
2015-11-18 15:06:25 +00:00
static Int del_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
Term otatts;
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
attvar_record *attv;
Term tatts = Deref(ARG2);
Functor mfun = FunctorOfTerm(tatts);
if (IsAttachedTerm(inp)) {
attv = RepAttVar(VarOfTerm(inp));
} else {
return TRUE;
}
2015-11-06 18:22:31 +00:00
if (IsVarTerm(otatts = SearchAttsForModule(attv->Atts, mfun))) {
return TRUE;
} else {
DelAtts(attv, otatts PASS_REGS);
}
return TRUE;
} else {
return TRUE;
}
}
2015-11-18 15:06:25 +00:00
static Int del_all_atts(USES_REGS1) {
2010-03-03 19:08:17 +00:00
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp) && IsAttachedTerm(inp)) {
attvar_record *attv;
2015-11-06 18:22:31 +00:00
attv = RepAttVar(VarOfTerm(inp));
DelAllAtts(attv PASS_REGS);
2015-11-06 18:22:31 +00:00
}
2010-03-03 19:08:17 +00:00
return TRUE;
}
2015-11-18 15:06:25 +00:00
static Int get_att(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
Atom modname = AtomOfTerm(Deref(ARG2));
if (IsAttachedTerm(inp)) {
attvar_record *attv;
Term tout, tatts;
attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
if (IsVarTerm(tatts = SearchAttsForModuleName(attv->Atts, modname)))
return FALSE;
tout = ArgOfTerm(IntegerOfTerm(Deref(ARG3)), tatts);
if (tout == TermVoidAtt)
return FALSE;
return Yap_unify(tout, ARG4);
} else {
/* Yap_Error(INSTANTIATION_ERROR,inp,"get_att/2"); */
return FALSE;
}
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of get_att/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int free_att(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
Atom modname = AtomOfTerm(Deref(ARG2));
if (IsAttachedTerm(inp)) {
attvar_record *attv;
Term tout, tatts;
attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
if (IsVarTerm(tatts = SearchAttsForModuleName(attv->Atts, modname)))
return TRUE;
tout = ArgOfTerm(IntegerOfTerm(Deref(ARG3)), tatts);
return (tout == TermVoidAtt);
} else {
/* Yap_Error(INSTANTIATION_ERROR,inp,"get_att/2"); */
return TRUE;
}
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of free_att/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int get_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv;
Term tatts;
Term access = Deref(ARG2);
Functor mfun = FunctorOfTerm(access);
UInt ar, i;
CELL *old, *new;
attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
if (IsVarTerm(tatts = SearchAttsForModule(attv->Atts, mfun)))
return FALSE;
ar = ArityOfFunctor(mfun);
2015-11-06 18:22:31 +00:00
new = RepAppl(access) + 2;
old = RepAppl(tatts) + 2;
for (i = 1; i < ar; i++, new ++, old++) {
if (*new != TermFreeTerm) {
if (*old == TermVoidAtt && *new != TermVoidAtt)
return FALSE;
if (*new == TermVoidAtt &&*old != TermVoidAtt)
return FALSE;
if (!Yap_unify(*new, *old))
return FALSE;
}
}
return TRUE;
} else {
/* Yap_Error(INSTANTIATION_ERROR,inp,"get_att/2"); */
return FALSE;
}
} else {
2015-11-06 18:22:31 +00:00
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int has_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv;
Term tatts;
Term access = Deref(ARG2);
Functor mfun = FunctorOfTerm(access);
attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
return !IsVarTerm(tatts = SearchAttsForModule(attv->Atts, mfun));
} else {
/* Yap_Error(INSTANTIATION_ERROR,inp,"get_att/2"); */
return FALSE;
}
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of has_atts/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int bind_attvar(USES_REGS1) {
/* receive a variable in ARG1 */
2015-11-06 18:22:31 +00:00
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
return (BindAttVar(attv PASS_REGS));
}
2015-11-06 18:22:31 +00:00
return (true);
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of bind_attvar/2");
return (false);
}
}
2015-11-18 15:06:25 +00:00
static Int unbind_attvar(USES_REGS1) {
/* receive a variable in ARG1 */
2015-11-06 18:22:31 +00:00
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
return (UnBindAttVar(attv));
}
2015-11-06 18:22:31 +00:00
return (TRUE);
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of bind_attvar/2");
return (FALSE);
}
}
2015-11-18 15:06:25 +00:00
static Int get_all_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv = RepAttVar(VarOfTerm(inp));
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG2, GetAllAtts(attv));
}
return TRUE;
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of get_all_atts/2");
return FALSE;
}
}
2015-11-06 18:22:31 +00:00
static int ActiveAtt(Term tatt, UInt ar) {
CELL *cp = RepAppl(tatt) + 1;
UInt i;
for (i = 1; i < ar; i++) {
if (cp[i] != TermVoidAtt)
return TRUE;
}
return FALSE;
}
2015-11-18 15:06:25 +00:00
static Int modules_with_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv = RepAttVar(VarOfTerm(inp));
2014-01-19 21:15:05 +00:00
CELL *h0 = HR;
Term tatt;
if (IsVarTerm(tatt = attv->Atts))
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG2, TermNil);
while (!IsVarTerm(tatt)) {
2015-11-06 18:22:31 +00:00
Functor f = FunctorOfTerm(tatt);
if (HR != h0)
HR[-1] = AbsPair(HR);
if (ActiveAtt(tatt, ArityOfFunctor(f))) {
*HR = MkAtomTerm(NameOfFunctor(f));
HR += 2;
}
tatt = ArgOfTerm(1, tatt);
}
2014-01-19 21:15:05 +00:00
if (h0 != HR) {
2015-11-06 18:22:31 +00:00
HR[-1] = TermNil;
return Yap_unify(ARG2, AbsPair(h0));
}
}
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG2, TermNil);
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of modules_with_attributes/2");
return FALSE;
}
}
2015-11-18 15:06:25 +00:00
static Int swi_all_atts(USES_REGS1) {
/* receive a variable in ARG1 */
Term inp = Deref(ARG1);
Functor attf = FunctorAtt1;
/* if this is unbound, ok */
if (IsVarTerm(inp)) {
if (IsAttachedTerm(inp)) {
attvar_record *attv = RepAttVar(VarOfTerm(inp));
2014-01-19 21:15:05 +00:00
CELL *h0 = HR;
Term tatt;
if (IsVarTerm(tatt = attv->Atts))
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG2, TermNil);
while (!IsVarTerm(tatt)) {
2015-11-06 18:22:31 +00:00
Functor f = FunctorOfTerm(tatt);
UInt ar = ArityOfFunctor(f);
if (HR != h0)
HR[-1] = AbsAppl(HR);
HR[0] = (CELL)attf;
HR[1] = MkAtomTerm(NameOfFunctor(f));
/* SWI */
if (ar == 2)
HR[2] = ArgOfTerm(2, tatt);
else
HR[2] = tatt;
HR += 4;
HR[-1] = AbsAppl(HR);
tatt = ArgOfTerm(1, tatt);
}
2014-01-19 21:15:05 +00:00
if (h0 != HR) {
2015-11-06 18:22:31 +00:00
HR[-1] = TermNil;
return Yap_unify(ARG2, AbsAppl(h0));
}
}
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG2, TermNil);
} else {
2015-11-06 18:22:31 +00:00
Yap_Error(REPRESENTATION_ERROR_VARIABLE, inp,
"first argument of get_all_swi_atts/2");
return FALSE;
}
}
2015-11-06 18:22:31 +00:00
static Term AllAttVars(USES_REGS1) {
2010-03-10 14:06:07 +00:00
CELL *pt = H0;
2014-01-19 21:15:05 +00:00
CELL *myH = HR;
2015-11-06 18:22:31 +00:00
2011-09-20 09:53:06 +01:00
while (pt < myH) {
2015-11-06 18:22:31 +00:00
switch (*pt) {
2018-05-10 13:11:56 +01:00
case (CELL)FunctorAttVar:
2015-11-06 18:22:31 +00:00
if (IsUnboundVar(pt + 1)) {
if (ASP - myH < 1024) {
LOCAL_Error_Size = (ASP - HR) * sizeof(CELL);
return 0L;
}
if (myH != HR) {
myH[-1] = AbsPair(myH);
}
myH[0] = AbsAttVar((attvar_record *)pt);
myH += 2;
2010-03-10 14:06:07 +00:00
}
2015-11-06 18:22:31 +00:00
pt += (1 + ATT_RECORD_ARITY);
2010-03-10 14:06:07 +00:00
break;
2018-05-10 13:11:56 +01:00
case (CELL)FunctorDouble:
2015-11-06 18:22:31 +00:00
#if SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
2010-03-10 14:06:07 +00:00
pt += 4;
#else
pt += 3;
#endif
break;
2018-05-10 13:11:56 +01:00
case (CELL)FunctorString:
2015-11-06 18:22:31 +00:00
pt += 3 + pt[1];
break;
2018-05-10 13:11:56 +01:00
case (CELL)FunctorBigInt: {
Int sz = 3 + (sizeof(MP_INT) +
(((MP_INT *)(pt + 2))->_mp_alloc * sizeof(mp_limb_t))) /
sizeof(CELL);
2015-11-06 18:22:31 +00:00
pt += sz;
} break;
2018-05-10 13:11:56 +01:00
case (CELL)FunctorLongInt:
2010-03-10 14:06:07 +00:00
pt += 3;
break;
default:
pt++;
}
}
2014-01-19 21:15:05 +00:00
if (myH != HR) {
Term out = AbsPair(HR);
2010-03-10 14:06:07 +00:00
myH[-1] = TermNil;
2014-01-19 21:15:05 +00:00
HR = myH;
2010-03-10 14:06:07 +00:00
return out;
} else {
return TermNil;
}
}
2015-11-06 18:22:31 +00:00
2015-11-18 15:06:25 +00:00
static Int all_attvars(USES_REGS1) {
2010-03-10 14:06:07 +00:00
do {
Term out;
2015-11-06 18:22:31 +00:00
if (!(out = AllAttVars(PASS_REGS1))) {
if (!Yap_gcl(LOCAL_Error_Size, 1, ENV, gc_P(P, CP))) {
Yap_Error(RESOURCE_ERROR_STACK, TermNil, LOCAL_ErrorMessage);
return FALSE;
}
2010-03-10 14:06:07 +00:00
} else {
2015-11-06 18:22:31 +00:00
return Yap_unify(ARG1, out);
2010-03-10 14:06:07 +00:00
}
} while (TRUE);
}
2015-11-06 18:22:31 +00:00
/** @pred attvar( _-Var_)
2015-01-04 23:58:23 +00:00
Succeed if _Var_ is an attributed variable.
*/
2015-11-18 15:06:25 +00:00
static Int is_attvar(USES_REGS1) {
Term t = Deref(ARG1);
2015-11-06 18:22:31 +00:00
return (IsVarTerm(t) && IsAttVar(VarOfTerm(t)));
}
/* check if we are not redoing effort */
2015-11-18 15:06:25 +00:00
static Int attvar_bound(USES_REGS1) {
Term t = Deref(ARG1);
2015-11-06 18:22:31 +00:00
return IsVarTerm(t) && IsAttachedTerm(t) &&
2018-05-10 13:11:56 +01:00
!IsUnboundVar(&(RepAttVar(VarOfTerm(t))->Done));
}
2015-11-18 15:06:25 +00:00
static Int void_term(USES_REGS1) { return Yap_unify(ARG1, TermVoidAtt); }
2015-11-18 15:06:25 +00:00
static Int free_term(USES_REGS1) { return Yap_unify(ARG1, TermFreeTerm); }
2015-11-18 15:06:25 +00:00
static Int fast_unify(USES_REGS1) {
/*
Case we want to unify two variables, but we do not
think there is a point in waking them up
*/
Term t1, t2;
CELL *a, *b;
if (!IsVarTerm(t1 = Deref(ARG1)))
return FALSE;
if (!IsVarTerm(t2 = Deref(ARG2)))
return FALSE;
a = VarOfTerm(t1);
b = VarOfTerm(t2);
2015-11-06 18:22:31 +00:00
if (a > b) {
Bind_Global_NonAtt(a, t2);
} else if ((a) < (b)) {
Bind_Global_NonAtt(b, t1);
}
return TRUE;
}
#else
2015-11-18 15:06:25 +00:00
static Int all_attvars(USES_REGS1) { return FALSE; }
2015-11-18 15:06:25 +00:00
static Int is_attvar(USES_REGS1) { return FALSE; }
2015-11-18 15:06:25 +00:00
static Int attvar_bound(USES_REGS1) { return FALSE; }
#endif /* COROUTINING */
2015-11-06 18:22:31 +00:00
void Yap_InitAttVarPreds(void) {
CACHE_REGS
2018-05-10 13:11:56 +01:00
Term OldCurrentModule = CurrentModule;
CurrentModule = ATTRIBUTES_MODULE;
#ifdef COROUTINING
GLOBAL_attas[attvars_ext].bind_op = WakeAttVar;
GLOBAL_attas[attvars_ext].copy_term_op = CopyAttVar;
GLOBAL_attas[attvars_ext].to_term_op = AttVarToTerm;
GLOBAL_attas[attvars_ext].term_to_op = TermToAttVar;
GLOBAL_attas[attvars_ext].mark_op = mark_attvar;
2015-11-18 15:06:25 +00:00
Yap_InitCPred("get_att", 4, get_att, SafePredFlag);
Yap_InitCPred("get_module_atts", 2, get_atts, SafePredFlag);
Yap_InitCPred("has_module_atts", 2, has_atts, SafePredFlag);
Yap_InitCPred("get_all_atts", 2, get_all_atts, SafePredFlag);
Yap_InitCPred("get_all_swi_atts", 2, swi_all_atts, SafePredFlag);
Yap_InitCPred("free_att", 3, free_att, SafePredFlag);
Yap_InitCPred("put_att", 5, put_att, 0);
Yap_InitCPred("put_att_term", 2, put_att_term, 0);
Yap_InitCPred("put_module_atts", 2, put_atts, 0);
Yap_InitCPred("del_all_module_atts", 2, del_atts, 0);
Yap_InitCPred("del_all_atts", 1, del_all_atts, 0);
Yap_InitCPred("rm_att", 4, rm_att, 0);
Yap_InitCPred("bind_attvar", 1, bind_attvar, SafePredFlag);
Yap_InitCPred("unbind_attvar", 1, unbind_attvar, SafePredFlag);
2018-05-10 13:11:56 +01:00
Yap_InitCPred("modules_with_attributes", 2, modules_with_atts, SafePredFlag);
2015-11-18 15:06:25 +00:00
Yap_InitCPred("void_term", 1, void_term, SafePredFlag);
Yap_InitCPred("free_term", 1, free_term, SafePredFlag);
Yap_InitCPred("fast_unify_attributed", 2, fast_unify, 0);
#endif /* COROUTINING */
2015-11-18 15:06:25 +00:00
Yap_InitCPred("all_attvars", 1, all_attvars, 0);
CurrentModule = OldCurrentModule;
2015-11-18 15:06:25 +00:00
Yap_InitCPred("attvar", 1, is_attvar, SafePredFlag | TestPredFlag);
Yap_InitCPred("$att_bound", 1, attvar_bound, SafePredFlag | TestPredFlag);
}
2015-01-04 23:58:23 +00:00
/** @} */