YAP 7.1.0
corout.c
1/*************************************************************************
2* *
3* YAP Prolog *
4* *
5* Yap Prolog was developed at NCCUP - Universidade do Porto *
6* *
7* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8* *
9**************************************************************************
10* *
11* File: corout.c *
12* Last rev: *
13* mods: *
14* comments: Co-routining from within YAP *
15* *
16*************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif
20
21#include "Yap.h"
22#include "Yatom.h"
23#include "YapHeap.h"
24#include "heapgc.h"
25#include "attvar.h"
26#ifndef NULL
27#define NULL (void *)0
28#endif
29
30#ifdef COROUTINING
31
32/* check if variable was there */
33static Term AddVarIfNotThere(Term var, Term dest USES_REGS) {
34 Term test = dest;
35 while (test != TermNil) {
36 if ((RepPair(test))[0] == var)
37 return (dest);
38 else
39 test = (RepPair(test))[1];
40 }
41 return (MkPairTerm(var, dest));
42}
43
44/* This routine verifies whether two complex structures can unify. */
45static int can_unify_complex(register CELL *pt0, register CELL *pt0_end,
46 register CELL *pt1, Term *Vars USES_REGS) {
47
48 /* This is really just unification, folks */
49 tr_fr_ptr saved_TR;
50 CELL *saved_HB;
51 choiceptr saved_B;
52
53 register CELL **to_visit = (CELL **)Yap_PreAllocCodeSpace();
54 CELL **to_visit_base = to_visit;
55
56 /* make sure to trail all bindings */
57 saved_TR = TR;
58 saved_B = B;
59 saved_HB = HB;
60 HB = HR;
61
62loop:
63 while (pt0 < pt0_end) {
64 register CELL d0, d1;
65 ++pt0;
66 ++pt1;
67 d0 = Derefa(pt0);
68 d1 = Derefa(pt1);
69 if (IsVarTerm(d0)) {
70 if (IsVarTerm(d1)) {
71 if (d0 != d1) {
72 /* we need to suspend on both variables ! */
73 *Vars = AddVarIfNotThere(d0, AddVarIfNotThere(d1, *Vars PASS_REGS)
74 PASS_REGS);
75 /* bind the two variables, we would have to do that to unify
76 them */
77 if (d1 > d0) { /* youngest */
78 /* we don't want to wake up goals */
79 Bind_Global_NonAtt((CELL *)d1, d0);
80 } else {
81 Bind_Global_NonAtt((CELL *)d0, d1);
82 }
83 }
84 /* continue the loop */
85 continue;
86 } else {
87 /* oh no, some more variables! */
88 *Vars = AddVarIfNotThere(d0, *Vars PASS_REGS);
89 }
90 /* now bind it */
91 Bind_Global_NonAtt((CELL *)d0, d1);
92 /* continue the loop */
93 } else if (IsVarTerm(d1)) {
94 *Vars = AddVarIfNotThere(d1, *Vars PASS_REGS);
95 /* and bind it */
96 Bind_Global_NonAtt((CELL *)d1, d0);
97 /* continue the loop */
98 } else {
99 if (d0 == d1)
100 continue;
101 if (IsAtomOrIntTerm(d0) || IsAtomOrIntTerm(d1)) {
102 if (d0 != d1)
103 goto comparison_failed;
104 /* else continue the loop */
105 } else if (IsPairTerm(d0)) {
106 if (!IsPairTerm(d1))
107 goto comparison_failed;
108#ifdef RATIONAL_TREES
109 to_visit[0] = pt0;
110 to_visit[1] = pt0_end;
111 to_visit[2] = pt1;
112 to_visit[3] = (CELL *)*pt0;
113 to_visit += 4;
114 *pt0 = d1;
115#else
116 /* store the terms to visit */
117 if (pt0 < pt0_end) {
118 to_visit[0] = pt0;
119 to_visit[1] = pt0_end;
120 to_visit[2] = pt1;
121 to_visit += 3;
122 }
123#endif
124 pt0 = RepPair(d0) - 1;
125 pt0_end = RepPair(d0) + 1;
126 pt1 = RepPair(d1) - 1;
127 continue;
128 } else if (IsApplTerm(d0)) {
129 register Functor f;
130 register CELL *ap2, *ap3;
131 if (!IsApplTerm(d1)) {
132 goto comparison_failed;
133 } else {
134 /* store the terms to visit */
135 ap2 = RepAppl(d0);
136 ap3 = RepAppl(d1);
137 f = (Functor)(*ap2);
138 /* compare functors */
139 if (f != (Functor)*ap3) {
140 goto comparison_failed;
141 }
142 if (IsExtensionFunctor(f)) {
143 switch ((CELL)f) {
144 case (CELL) FunctorDBRef:
145 if (d0 == d1)
146 continue;
147 goto comparison_failed;
148 case (CELL) FunctorLongInt:
149 if (ap2[1] == ap3[1])
150 continue;
151 goto comparison_failed;
152 case (CELL) FunctorDouble:
153 if (FloatOfTerm(d0) == FloatOfTerm(d1))
154 continue;
155 goto comparison_failed;
156 case (CELL) FunctorString:
157 if (strcmp((char *)StringOfTerm(d0), (char *)StringOfTerm(d1)) ==
158 0)
159 continue;
160 goto comparison_failed;
161#ifdef USE_GMP
162 case (CELL) FunctorBigInt:
163 if (Yap_gmp_tcmp_big_big(d0, d1) == 0)
164 continue;
165 goto comparison_failed;
166#endif /* USE_GMP */
167 default:
168 goto comparison_failed;
169 }
170 }
171#ifdef RATIONAL_TREES
172 to_visit[0] = pt0;
173 to_visit[1] = pt0_end;
174 to_visit[2] = pt1;
175 to_visit[3] = (CELL *)*pt0;
176 to_visit += 4;
177 *pt0 = d1;
178#else
179 /* store the terms to visit */
180 if (pt0 < pt0_end) {
181 to_visit[0] = pt0;
182 to_visit[1] = pt0_end;
183 to_visit[2] = pt1;
184 to_visit += 3;
185 }
186#endif
187 d0 = ArityOfFunctor(f);
188 pt0 = ap2;
189 pt0_end = ap2 + d0;
190 pt1 = ap3;
191 continue;
192 }
193 }
194 }
195 }
196 /* Do we still have compound terms to visit */
197 if (to_visit > (CELL **)to_visit_base) {
198#ifdef RATIONAL_TREES
199 to_visit -= 4;
200 pt0 = to_visit[0];
201 pt0_end = to_visit[1];
202 pt1 = to_visit[2];
203 *pt0 = (CELL)to_visit[3];
204#else
205 to_visit -= 3;
206 pt0 = to_visit[0];
207 pt0_end = to_visit[1];
208 pt1 = to_visit[2];
209#endif
210 goto loop;
211 }
212 /* success */
213 Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
214 /* restore B, and later HB */
215 B = saved_B;
216 HB = saved_HB;
217 /* untrail all bindings made by IUnify */
218 while (TR != saved_TR) {
219 pt1 = (CELL *)(TrailTerm(--TR));
220 RESET_VARIABLE(pt1);
221 }
222 return (TRUE);
223
224comparison_failed:
225 /* failure */
226 Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
227#ifdef RATIONAL_TREES
228 while (to_visit > (CELL **)to_visit_base) {
229 to_visit -= 4;
230 pt0 = to_visit[0];
231 pt0_end = to_visit[1];
232 pt1 = to_visit[2];
233 *pt0 = (CELL)to_visit[3];
234 }
235#endif
236 /* restore B, and later HB */
237 B = saved_B;
238 HB = saved_HB;
239 /* untrail all bindings made by IUnify */
240 while (TR != saved_TR) {
241 pt1 = (CELL *)(TrailTerm(--TR));
242 RESET_VARIABLE(pt1);
243 }
244 /* the system will take care of TR for me, no need to worry here! */
245 return (FALSE);
246}
247
248static int can_unify(Term t1, Term t2, Term *Vars USES_REGS) {
249 t1 = Deref(t1);
250 t2 = Deref(t2);
251 if (t1 == t2) {
252 *Vars = TermNil;
253 return TRUE;
254 }
255 if (IsVarTerm(t1)) {
256 /* we know for sure they can't be different */
257 if (IsVarTerm(t2)) {
258 /* we need to suspend on both variables because otherwise
259 Y = susp(_) would not wakeup susp ! */
260 *Vars = MkPairTerm(t1, MkPairTerm(t2, TermNil));
261 return TRUE;
262 } else {
263 *Vars = MkPairTerm(t1, TermNil);
264 return TRUE;
265 }
266 } else if (IsVarTerm(t2)) {
267 /* wait until t2 is bound */
268 *Vars = MkPairTerm(t2, TermNil);
269 return TRUE;
270 }
271 /* Two standard terms at last! */
272 if (IsAtomOrIntTerm(t1) || IsAtomOrIntTerm(t2)) {
273 /* Two primitive terms can only be equal if they are
274 the same. If they are, $eq succeeds without further ado.
275 */
276 if (t1 != t2)
277 return FALSE;
278 else {
279 *Vars = TermNil;
280 return TRUE;
281 }
282 } else if (IsPairTerm(t1)) {
283 if (IsPairTerm(t2)) {
284 return (can_unify_complex(RepPair(t1) - 1, RepPair(t1) + 1,
285 RepPair(t2) - 1, Vars PASS_REGS));
286 } else
287 return FALSE;
288 } else {
289 Functor f = FunctorOfTerm(t1);
290 if (f != FunctorOfTerm(t2))
291 return FALSE;
292 if (IsExtensionFunctor(f)) {
293 switch ((CELL)f) {
294 case (CELL) FunctorDBRef:
295 if (t1 == t2)
296 return FALSE;
297 return FALSE;
298 case (CELL) FunctorLongInt:
299 if (RepAppl(t1)[1] == RepAppl(t2)[1])
300 return (TRUE);
301 return FALSE;
302 case (CELL) FunctorString:
303 if (strcmp((char *)StringOfTerm(t1), (char *)StringOfTerm(t2)) == 0)
304 return (TRUE);
305 return FALSE;
306 case (CELL) FunctorDouble:
307 if (FloatOfTerm(t1) == FloatOfTerm(t2))
308 return (TRUE);
309 return FALSE;
310#ifdef USE_GMP
311 case (CELL) FunctorBigInt:
312 if (Yap_gmp_tcmp_big_big(t1, t2) == 0)
313 return (TRUE);
314 return (FALSE);
315#endif /* USE_GMP */
316 default:
317 return FALSE;
318 }
319 }
320 /* Two complex terms with the same functor */
321 return can_unify_complex(RepAppl(t1), RepAppl(t1) + ArityOfFunctor(f),
322 RepAppl(t2), Vars PASS_REGS);
323 }
324}
325
326/* This routine verifies whether a complex has variables. */
327static int non_ground_complex(register CELL *pt0, register CELL *pt0_end,
328 Term *Var USES_REGS) {
329
330 register CELL **to_visit = (CELL **)Yap_PreAllocCodeSpace();
331 CELL **to_visit_base = to_visit;
332
333loop:
334 while (pt0 < pt0_end) {
335 register CELL d0;
336 ++pt0;
337 d0 = Derefa(pt0);
338 if (IsVarTerm(d0)) {
339 *Var = d0;
340 goto var_found;
341 }
342 if (IsPairTerm(d0)) {
343 if (to_visit + 1024 >= (CELL **)AuxSp) {
344 goto aux_overflow;
345 }
346#ifdef RATIONAL_TREES
347 to_visit[0] = pt0;
348 to_visit[1] = pt0_end;
349 to_visit[2] = (CELL *)*pt0;
350 to_visit += 3;
351 *pt0 = TermNil;
352#else
353 /* store the terms to visit */
354 if (pt0 < pt0_end) {
355 to_visit[0] = pt0;
356 to_visit[1] = pt0_end;
357 to_visit += 2;
358 }
359#endif
360 pt0 = RepPair(d0) - 1;
361 pt0_end = RepPair(d0) + 1;
362 } else if (IsApplTerm(d0)) {
363 register Functor f;
364 register CELL *ap2;
365
366 /* store the terms to visit */
367 ap2 = RepAppl(d0);
368 f = (Functor)(*ap2);
369
370 if (IsExtensionFunctor(f)) {
371 continue;
372 }
373 if (to_visit + 1024 >= (CELL **)AuxSp) {
374 goto aux_overflow;
375 }
376#ifdef RATIONAL_TREES
377 to_visit[0] = pt0;
378 to_visit[1] = pt0_end;
379 to_visit[2] = (CELL *)*pt0;
380 to_visit += 3;
381 *pt0 = TermNil;
382#else
383 /* store the terms to visit */
384 if (pt0 < pt0_end) {
385 to_visit[0] = pt0;
386 to_visit[1] = pt0_end;
387 to_visit += 2;
388 }
389#endif
390 d0 = ArityOfFunctor(f);
391 pt0 = ap2;
392 pt0_end = ap2 + d0;
393 }
394 /* just continue the loop */
395 }
396
397 /* Do we still have compound terms to visit */
398 if (to_visit > (CELL **)to_visit_base) {
399#ifdef RATIONAL_TREES
400 to_visit -= 3;
401 pt0 = to_visit[0];
402 pt0_end = to_visit[1];
403 *pt0 = (CELL)to_visit[2];
404#else
405 to_visit -= 2;
406 pt0 = to_visit[0];
407 pt0_end = to_visit[1];
408#endif
409 goto loop;
410 }
411
412 /* the term is ground */
413 Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
414 return FALSE;
415
416var_found:
417 /* the term is non-ground */
418 Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
419#ifdef RATIONAL_TREES
420 while (to_visit > (CELL **)to_visit_base) {
421 to_visit -= 3;
422 pt0 = to_visit[0];
423 pt0_end = to_visit[1];
424 *pt0 = (CELL)to_visit[2];
425 }
426#endif
427 /* the system will take care of TR for me, no need to worry here! */
428 return TRUE;
429
430aux_overflow:
431 /* unwind stack */
432 Yap_ReleasePreAllocCodeSpace((ADDR)to_visit);
433#ifdef RATIONAL_TREES
434 while (to_visit > (CELL **)to_visit_base) {
435 to_visit -= 3;
436 pt0 = to_visit[0];
437 *pt0 = (CELL)to_visit[2];
438 }
439#endif
440 return -1;
441}
442
443static int non_ground(Term t, Term *Var USES_REGS) {
444 int out = -1;
445 while (out < 0) {
446 t = Deref(t);
447 if (IsVarTerm(t)) {
448 /* we found a variable */
449 *Var = t;
450 return TRUE;
451 }
452 if (IsPrimitiveTerm(t)) {
453 return FALSE;
454 } else if (IsPairTerm(t)) {
455 out = non_ground_complex(RepPair(t) - 1, RepPair(t) + 1, Var PASS_REGS);
456 if (out >= 0)
457 return out;
458 } else {
459 Functor f = FunctorOfTerm(t);
460 if (IsExtensionFunctor(f)) {
461 return FALSE;
462 }
463 out = non_ground_complex(RepAppl(t),
464 RepAppl(t) + ArityOfFunctor(FunctorOfTerm(t)),
465 Var PASS_REGS);
466 if (out >= 0)
467 return out;
468 }
469 if (!Yap_ExpandPreAllocCodeSpace(0, NULL, TRUE)) {
470 Yap_Error(RESOURCE_ERROR_AUXILIARY_STACK, ARG1, "overflow in ground");
471 return FALSE;
472 }
473 }
474 return FALSE;
475}
476
477#endif
478
479/* check whether the two terms unify and return what variables should
480 be bound before the terms are exactly equal */
481static Int p_can_unify(USES_REGS1) {
482#ifdef COROUTINING
483 Term r = TermNil;
484 if (!can_unify(ARG1, ARG2, &r PASS_REGS))
485 return FALSE;
486 return Yap_unify(ARG3, r);
487#else
488 return FALSE;
489#endif
490}
491
492/* if the term is not ground return a variable in the term */
493static Int p_non_ground(USES_REGS1) {
494#ifdef COROUTINING
495 Term r = TermNil;
496 if (!non_ground(ARG1, &r PASS_REGS))
497 return (FALSE);
498 return (Yap_unify(ARG2, r));
499#else
500 return (FALSE);
501#endif
502}
503
504/* if the term is not ground return a variable in the term */
505static Int p_coroutining(USES_REGS1) {
506#ifdef COROUTINING
507 return (TRUE);
508#else
509 return (FALSE);
510#endif
511}
512
513#if COROUTINING
514static Term ListOfWokenGoals(USES_REGS1) {
515 return Yap_ReadTimedVar(LOCAL_WokenGoals);
516}
517
518Term Yap_ListOfWokenGoals(void) {
519 CACHE_REGS
520 return ListOfWokenGoals(PASS_REGS1);
521}
522#endif
523
524/* return a list of awoken goals */
525static Int p_awoken_goals(USES_REGS1) {
526#ifdef COROUTINING
527 Term WGs = Yap_ReadTimedVar(LOCAL_WokenGoals);
528 if (WGs == TermNil) {
529 return (FALSE);
530 }
531 WGs = ListOfWokenGoals(PASS_REGS1);
532 Yap_UpdateTimedVar(LOCAL_WokenGoals, TermTrue);
533 return (Yap_unify(ARG1, WGs));
534#else
535 return (FALSE);
536#endif
537}
538
539static Int p_yap_has_rational_trees(USES_REGS1) {
540#if RATIONAL_TREES
541 return TRUE;
542#else
543 return FALSE;
544#endif
545}
546
547static Int p_yap_has_coroutining(USES_REGS1) {
548#if COROUTINING
549 return TRUE;
550#else
551 return FALSE;
552#endif
553}
554
555void Yap_InitCoroutPreds(void) {
556#ifdef COROUTINING
557 Atom at;
558 PredEntry *pred;
559
560 at = AtomWakeUpGoal;
561 pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 2), 0));
562 WakeUpCode = pred;
563#endif
564 Yap_InitAttVarPreds();
565 Yap_InitCPred("$yap_has_rational_trees", 0, p_yap_has_rational_trees,
566 SafePredFlag);
567 Yap_InitCPred("$yap_has_coroutining", 0, p_yap_has_coroutining, SafePredFlag);
568 Yap_InitCPred("$can_unify", 3, p_can_unify, SafePredFlag);
569 Yap_InitCPred("$non_ground", 2, p_non_ground, SafePredFlag);
570 Yap_InitCPred("$coroutining", 0, p_coroutining, SafePredFlag);
571 Yap_InitCPred("$awoken_goals", 1, p_awoken_goals, SafePredFlag);
572}
Main definitions.
Definition: Yatom.h:544