unfy.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. /* This file is part of unfy.
  2. *
  3. * Unfy is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Lesser General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * Unfy is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public License
  14. * along with unfy. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <rid.h>
  17. #include <stdlib.h>
  18. #define STYLE_9
  19. #include "unfy.h"
  20. #define SWAP(ptr1, ptr2) \
  21. do { void *SWAP = ptr1; ptr1 = ptr2; ptr2 = SWAP; } while (0)
  22. static Unfy_term *
  23. get_term(Unfy_recycle *rec)
  24. {
  25. Unfy_term *term = rec->terms;
  26. if (!term)
  27. return malloc(sizeof(*term));
  28. rec->terms = term->u.dat;
  29. return term;
  30. }
  31. static Unfy_list *
  32. get_list(Unfy_recycle *rec)
  33. {
  34. Unfy_list *list = rec->lists;
  35. if (!list)
  36. return malloc(sizeof(*list));
  37. rec->lists = list->next;
  38. return list;
  39. }
  40. static Unfy_bind *
  41. get_bind(Unfy_recycle *rec)
  42. {
  43. Unfy_bind *bind = rec->binds;
  44. if (!bind)
  45. return malloc(sizeof(*bind));
  46. rec->binds = bind->next;
  47. return bind;
  48. }
  49. void
  50. unfy_recycle_init(Unfy_recycle *rec)
  51. {
  52. rec->terms = NULL;
  53. rec->lists = NULL;
  54. rec->binds = NULL;
  55. }
  56. void
  57. unfy_recycle_empty(Unfy_recycle *rec)
  58. {
  59. while (rec->terms) {
  60. Unfy_term *term = rec->terms;
  61. rec->terms = term->u.dat;
  62. free(term);
  63. }
  64. while (rec->lists) {
  65. Unfy_list *tmp = rec->lists;
  66. rec->lists = tmp->next;
  67. free(tmp);
  68. }
  69. while (rec->binds) {
  70. Unfy_bind *tmp = rec->binds;
  71. rec->binds = tmp->next;
  72. free(tmp);
  73. }
  74. }
  75. void
  76. unfy_recycle_term(Unfy_recycle *rec, Unfy_term *term)
  77. {
  78. if (!term)
  79. return;
  80. switch (term->type) {
  81. case UNFY_LIST:
  82. unfy_recycle_list(rec, term->u.list);
  83. /* fall through */
  84. case UNFY_CONST:
  85. case UNFY_ORDER:
  86. case UNFY_IGN:
  87. case UNFY_VAR:
  88. term->u.dat = rec->terms;
  89. rec->terms = term;
  90. }
  91. }
  92. void
  93. unfy_recycle_list(Unfy_recycle *rec, Unfy_list *list)
  94. {
  95. Unfy_list *end = list;
  96. if (!list)
  97. return;
  98. while (1) {
  99. unfy_recycle_term(rec, end->term);
  100. if (!end->next)
  101. break;
  102. end = end->next;
  103. }
  104. end->next = rec->lists;
  105. rec->lists = list;
  106. }
  107. void
  108. unfy_recycle_bind(Unfy_recycle *rec, Unfy_bind *bind)
  109. {
  110. Unfy_bind *end = bind;
  111. if (!bind)
  112. return;
  113. while (1) {
  114. unfy_recycle_term(rec, end->term);
  115. if (!end->next)
  116. break;
  117. end = end->next;
  118. }
  119. end->next = rec->binds;
  120. rec->binds = bind;
  121. }
  122. Unfy_term *
  123. unfy_term(Unfy_type type, void *dat, Unfy_recycle *rec)
  124. {
  125. Unfy_term *term = get_term(rec);
  126. if (!term)
  127. return NULL;
  128. unfy_term_init(term, type, dat);
  129. return term;
  130. }
  131. Unfy_term *
  132. unfy_term_id(Unfy_type type, const Rid id, Unfy_recycle *rec)
  133. {
  134. Unfy_term *term = get_term(rec);
  135. if (!term)
  136. return NULL;
  137. term->type = type;
  138. rid_set(term->u.id, id);
  139. return term;
  140. }
  141. Unfy_term *
  142. unfy_term_copy(const Unfy_term *term, Unfy_recycle *rec)
  143. {
  144. Unfy_term *copy = get_term(rec);
  145. if (!copy)
  146. return NULL;
  147. if (unfy_term_init_copy(copy, term, rec) < 0) {
  148. unfy_recycle_term(rec, copy);
  149. return NULL;
  150. }
  151. return copy;
  152. }
  153. void
  154. unfy_term_init(Unfy_term *term, Unfy_type type, void *dat)
  155. {
  156. switch ((term->type = type)) {
  157. case UNFY_ORDER:
  158. term->u.order = *(size_t *) dat;
  159. break;
  160. case UNFY_IGN:
  161. break;
  162. case UNFY_CONST:
  163. /* fallthru */
  164. case UNFY_VAR:
  165. rid_set(term->u.id, dat);
  166. break;
  167. case UNFY_LIST:
  168. term->u.list = dat;
  169. break;
  170. }
  171. }
  172. int
  173. unfy_term_init_copy(Unfy_term *des, const Unfy_term *src, Unfy_recycle *rec)
  174. {
  175. Unfy_list *list = NULL;
  176. switch (src->type) {
  177. case UNFY_CONST:
  178. case UNFY_VAR:
  179. rid_set(des->u.id, src->u.id);
  180. break;
  181. case UNFY_ORDER:
  182. des->u.order = src->u.order;
  183. break;
  184. case UNFY_IGN:
  185. break;
  186. case UNFY_LIST:
  187. if (src->u.list && unfy_list_copy(&list, src->u.list, rec) < 0)
  188. return -1;
  189. des->u.list = list;
  190. break;
  191. }
  192. des->type = src->type;
  193. return 0;
  194. }
  195. Unfy_stat
  196. unfy_list_same(Unfy_info *info, Unfy_list *llist, Unfy_list *rlist,
  197. Unfy_recycle *rec)
  198. {
  199. Unfy_term *tmp_left = info->left;
  200. Unfy_term *tmp_right = info->right;
  201. Unfy_stat stat;
  202. for (; llist; llist = llist->next, rlist = rlist->next) {
  203. if (!rlist) {
  204. info->rsn = UNFY_RSN_LEN;
  205. return UNFY_NO;
  206. }
  207. info->left = llist->term;
  208. info->right = rlist->term;
  209. stat = unfy_term_same(info, rec);
  210. if (stat != UNFY_YES)
  211. return stat;
  212. info->left = tmp_left;
  213. info->right = tmp_right;
  214. }
  215. if (rlist) {
  216. info->rsn = UNFY_RSN_LEN;
  217. return UNFY_NO;
  218. }
  219. return UNFY_YES;
  220. }
  221. Unfy_stat
  222. unfy_term_same(Unfy_info *info, Unfy_recycle *rec)
  223. {
  224. Unfy_term *copy;
  225. if (info->left->type != info->right->type) {
  226. info->rsn = UNFY_RSN_TYPE;
  227. return UNFY_NO;
  228. }
  229. switch (info->right->type) {
  230. case UNFY_CONST:
  231. if (!rid_cmp(info->left->u.id, info->right->u.id))
  232. return UNFY_YES;
  233. info->rsn = UNFY_RSN_VAL;
  234. return UNFY_NO;
  235. case UNFY_ORDER:
  236. if (info->left->u.order == info->right->u.order)
  237. return UNFY_YES;
  238. info->rsn = UNFY_RSN_VAL;
  239. return UNFY_NO;
  240. case UNFY_IGN:
  241. return UNFY_YES;
  242. case UNFY_LIST:
  243. return unfy_list_same(info, info->left->u.list,
  244. info->right->u.list, rec);
  245. case UNFY_VAR:
  246. if ((copy = unfy_bind_get(info->lbind, info->left->u.id))) {
  247. if (!rid_cmp(copy->u.id, info->right->u.id))
  248. return UNFY_YES;
  249. info->rsn = UNFY_RSN_FORM;
  250. return UNFY_NO;
  251. }
  252. if (!(copy = unfy_term_copy(info->right, rec)))
  253. break;
  254. if (unfy_bind(&info->lbind, info->left->u.id, copy, rec) < 0) {
  255. unfy_recycle_term(rec, copy);
  256. break;
  257. }
  258. return UNFY_YES;
  259. }
  260. return UNFY_ERR;
  261. }
  262. static int
  263. has_var(const Unfy_term *term, const Rid var_id)
  264. {
  265. const Unfy_list *list;
  266. switch (term->type) {
  267. case UNFY_CONST:
  268. case UNFY_ORDER:
  269. case UNFY_IGN:
  270. break;
  271. case UNFY_LIST:
  272. list = term->u.list;
  273. for (; list; list = list->next)
  274. if (has_var(list->term, var_id))
  275. return 1;
  276. break;
  277. case UNFY_VAR:
  278. return !rid_cmp(term->u.id, var_id);
  279. }
  280. return 0;
  281. }
  282. int
  283. unfy_term_revar(const Unfy_term *term, Unfy_bind **bind, Unfy_recycle *rec)
  284. {
  285. const Unfy_list *list;
  286. Unfy_term *var;
  287. switch (term->type) {
  288. case UNFY_CONST:
  289. case UNFY_ORDER:
  290. case UNFY_IGN:
  291. return 0;
  292. case UNFY_LIST:
  293. if (!(list = term->u.list))
  294. return 0;
  295. for (; list; list = list->next)
  296. if (unfy_term_revar(list->term, bind, rec) < 0)
  297. return -1;
  298. return 0;
  299. case UNFY_VAR:
  300. if (unfy_bind_get(*bind, term->u.id))
  301. return 0;
  302. if (!(var = unfy_term(UNFY_VAR, NULL, rec))) {
  303. unfy_recycle_bind(rec, *bind);
  304. *bind = NULL;
  305. return -1;
  306. }
  307. if (unfy_bind(bind, term->u.id, var, rec) < 0) {
  308. unfy_recycle_term(rec, var);
  309. unfy_recycle_bind(rec, *bind);
  310. *bind = NULL;
  311. return -1;
  312. }
  313. return 0;
  314. }
  315. unfy_recycle_bind(rec, *bind);
  316. *bind = NULL;
  317. return -1;
  318. }
  319. Unfy_list *
  320. unfy_list(Unfy_term *term, Unfy_list *next, Unfy_recycle *rec)
  321. {
  322. Unfy_list *list = get_list(rec);
  323. if (!list)
  324. return NULL;
  325. unfy_list_init(list, term, next);
  326. return list;
  327. }
  328. int
  329. unfy_list_copy(Unfy_list **copy, const Unfy_list *list, Unfy_recycle *rec)
  330. {
  331. Unfy_list *head = NULL;
  332. Unfy_list **tail = &head;
  333. for (; list; list = list->next) {
  334. Unfy_term *term = unfy_term_copy(list->term, rec);
  335. if (!term) {
  336. unfy_recycle_list(rec, head);
  337. *copy = NULL;
  338. return -1;
  339. }
  340. if (!(tail = unfy_list_append(tail, term, rec))) {
  341. unfy_recycle_term(rec, term);
  342. unfy_recycle_list(rec, head);
  343. *copy = NULL;
  344. return -1;
  345. }
  346. }
  347. *copy = head;
  348. return 0;
  349. }
  350. void
  351. unfy_list_init(Unfy_list *list, Unfy_term *term, Unfy_list *next)
  352. {
  353. list->term = term;
  354. list->next = next;
  355. }
  356. int
  357. unfy_list_init_copy(Unfy_list *copy, const Unfy_list *list, Unfy_recycle *rec)
  358. {
  359. Unfy_term *term = unfy_term_copy(list->term, rec);
  360. Unfy_list *next;
  361. if (!term)
  362. return -1;
  363. if (unfy_list_copy(&next, list->next, rec) < 0) {
  364. unfy_recycle_term(rec, term);
  365. return -1;
  366. }
  367. unfy_list_init(copy, term, next);
  368. return 0;
  369. }
  370. Unfy_list **
  371. unfy_list_append(Unfy_list **tail, Unfy_term *term, Unfy_recycle *rec)
  372. {
  373. Unfy_list *new_tail = get_list(rec);
  374. if (!new_tail)
  375. return NULL;
  376. new_tail->term = term;
  377. new_tail->next = NULL;
  378. *tail = new_tail;
  379. return &new_tail->next;
  380. }
  381. int
  382. unfy_bind(Unfy_bind **bind, const Rid var_id, Unfy_term *term,
  383. Unfy_recycle *rec)
  384. {
  385. Unfy_bind *new_bind = get_bind(rec);
  386. if (!new_bind)
  387. return -1;
  388. new_bind->next = *bind;
  389. rid_set(new_bind->var_id, var_id);
  390. new_bind->term = term;
  391. *bind = new_bind;
  392. return 0;
  393. }
  394. Unfy_bind *
  395. unfy_bind_copy(const Unfy_bind *bind, Unfy_recycle *rec)
  396. {
  397. Unfy_bind *copy = NULL;
  398. for (; bind; bind = bind->next) {
  399. Unfy_term *term = unfy_term_copy(bind->term, rec);
  400. if (!term) {
  401. unfy_recycle_bind(rec, copy);
  402. return NULL;
  403. }
  404. if (unfy_bind(&copy, bind->var_id, term, rec) < 0) {
  405. unfy_recycle_bind(rec, copy);
  406. unfy_recycle_term(rec, term);
  407. return NULL;
  408. }
  409. }
  410. return copy;
  411. }
  412. Unfy_term *
  413. unfy_bind_get(const Unfy_bind *bind, const Rid var_id)
  414. {
  415. for (; bind; bind = bind->next)
  416. if (!rid_cmp(bind->var_id, var_id))
  417. return bind->term;
  418. return NULL;
  419. }
  420. static Unfy_stat
  421. term_replace(Unfy_term *term, const Rid var_id, const Unfy_term *val,
  422. Unfy_recycle *rec)
  423. {
  424. Unfy_list *list;
  425. switch (term->type) {
  426. case UNFY_CONST:
  427. case UNFY_ORDER:
  428. case UNFY_IGN:
  429. /* will never happen */
  430. return UNFY_ERR;
  431. case UNFY_LIST:
  432. list = term->u.list;
  433. for (; list; list = list->next)
  434. if (term_replace(list->term, var_id, val, rec) != UNFY_YES)
  435. return UNFY_ERR;
  436. break;
  437. case UNFY_VAR:
  438. if (!rid_cmp(term->u.id, var_id) &&
  439. unfy_term_init_copy(term, val, rec) < 0)
  440. return UNFY_ERR;
  441. break;
  442. }
  443. return UNFY_YES;
  444. }
  445. Unfy_stat
  446. unfy_bind_replace(Unfy_bind *bind, const Rid var_id, const Unfy_term *val,
  447. Unfy_recycle *rec)
  448. {
  449. for (; bind; bind = bind->next) {
  450. /* if the term does not have the var, ignore */
  451. if (!has_var(bind->term, var_id))
  452. continue;
  453. /* var cannot be replaced by a list containing itself */
  454. if (val->type == UNFY_LIST && has_var(val, bind->var_id))
  455. return UNFY_NO;
  456. /* shared var cannot be replaced by a list containing itself */
  457. if (bind->term->type == UNFY_VAR && val->type == UNFY_LIST &&
  458. has_var(val, bind->term->u.id))
  459. return UNFY_NO;
  460. if (term_replace(bind->term, var_id, val, rec) != UNFY_YES)
  461. return UNFY_ERR;
  462. }
  463. return UNFY_YES;
  464. }
  465. Unfy_term *
  466. unfy_term_bind(const Unfy_term *term, const Unfy_bind *bind, Unfy_recycle *rec)
  467. {
  468. Unfy_term *copy = unfy_term_copy(term, rec);
  469. if (!copy)
  470. return NULL;
  471. if (unfy_term_bind_set(copy, bind, rec) < 0) {
  472. unfy_recycle_term(rec, copy);
  473. return NULL;
  474. }
  475. return copy;
  476. }
  477. int
  478. unfy_term_bind_set(Unfy_term *term, const Unfy_bind *bind, Unfy_recycle *rec)
  479. {
  480. Unfy_list *list;
  481. const Unfy_term *val;
  482. switch (term->type) {
  483. case UNFY_CONST:
  484. case UNFY_ORDER:
  485. case UNFY_IGN:
  486. break;
  487. case UNFY_VAR:
  488. if (!(val = unfy_bind_get(bind, term->u.id)))
  489. break;
  490. return unfy_term_init_copy(term, val, rec);
  491. case UNFY_LIST:
  492. list = term->u.list;
  493. for (; list; list = list->next)
  494. if (unfy_term_bind_set(list->term, bind, rec) < 0)
  495. return -1;
  496. break;
  497. }
  498. return 0;
  499. }
  500. static Unfy_stat
  501. unify_consts(Unfy_info *info, Unfy_recycle *rec)
  502. {
  503. (void) rec;
  504. if (rid_cmp(info->left->u.id, info->right->u.id)) {
  505. info->rsn = UNFY_RSN_VAL;
  506. return UNFY_NO;
  507. }
  508. return UNFY_YES;
  509. }
  510. static Unfy_stat
  511. unify_orders(Unfy_info *info, Unfy_recycle *rec)
  512. {
  513. (void) rec;
  514. if (info->left->u.order != info->right->u.order) {
  515. info->rsn = UNFY_RSN_VAL;
  516. return UNFY_NO;
  517. }
  518. return UNFY_YES;
  519. }
  520. static Unfy_stat
  521. dont_unify(Unfy_info *info, Unfy_recycle *rec)
  522. {
  523. (void) rec;
  524. info->rsn = UNFY_RSN_TYPE;
  525. return UNFY_NO;
  526. }
  527. static Unfy_stat
  528. unify_lists(Unfy_info *info, Unfy_recycle *rec)
  529. {
  530. Unfy_list *llist = info->left->u.list;
  531. Unfy_list *rlist = info->right->u.list;
  532. Unfy_term *tmp_left = info->left;
  533. Unfy_term *tmp_right = info->right;
  534. Unfy_stat stat;
  535. for (; llist; llist = llist->next, rlist = rlist->next) {
  536. if (!rlist) {
  537. info->rsn = UNFY_RSN_LEN;
  538. return UNFY_NO;
  539. }
  540. info->left = llist->term;
  541. info->right = rlist->term;
  542. stat = unfy_unify(info, rec);
  543. if (stat != UNFY_YES)
  544. return stat;
  545. info->left = tmp_left;
  546. info->right = tmp_right;
  547. }
  548. if (rlist) {
  549. info->rsn = UNFY_RSN_LEN;
  550. return UNFY_NO;
  551. }
  552. return UNFY_YES;
  553. }
  554. /* only use with a var_id from top level term since var_id is not copied */
  555. static Unfy_stat
  556. bind_add(Unfy_bind **primary, Unfy_bind **secondary,
  557. const Rid var_id, const Unfy_term *val,
  558. Unfy_recycle *rec)
  559. {
  560. Unfy_term *bound = unfy_term_bind(val, *secondary, rec);
  561. if (!bound)
  562. return UNFY_ERR;
  563. /* var cannot be replaced by a list containing itself */
  564. if (bound->type == UNFY_LIST && has_var(bound, var_id)) {
  565. unfy_recycle_term(rec, bound);
  566. return UNFY_NO;
  567. }
  568. if (unfy_bind(primary, var_id, bound, rec) < 0) {
  569. unfy_recycle_term(rec, bound);
  570. return UNFY_ERR;
  571. }
  572. return unfy_bind_replace(*secondary, var_id, bound, rec);
  573. }
  574. static Unfy_stat
  575. bind_set(Unfy_bind **primary, Unfy_bind **secondary,
  576. Rid var_id, const Unfy_term *val, Unfy_recycle *rec)
  577. {
  578. Unfy_term *bound = unfy_term_bind(val, *secondary, rec);
  579. Rid var_id2; /* var_id can be overwritten in replacement */
  580. Unfy_stat stat;
  581. if (!bound)
  582. return UNFY_ERR;
  583. rid_set(var_id2, var_id);
  584. if ((stat = unfy_bind_replace(*primary, var_id2, bound, rec)) == UNFY_YES)
  585. stat = unfy_bind_replace(*secondary, var_id2, bound, rec);
  586. unfy_recycle_term(rec, bound);
  587. return stat;
  588. }
  589. static Unfy_stat
  590. unify_nonvar_var(Unfy_info *info, Unfy_recycle *rec)
  591. {
  592. Unfy_term *val = unfy_bind_get(info->rbind, info->right->u.id);
  593. Unfy_stat stat;
  594. if (!val) {
  595. if ((stat = bind_add(&info->rbind, &info->lbind,
  596. info->right->u.id, info->left,
  597. rec)) == UNFY_NO)
  598. goto no;
  599. return stat;
  600. }
  601. if (val->type == UNFY_VAR) {
  602. if ((stat = bind_set(&info->rbind, &info->lbind,
  603. val->u.id, info->left, rec)) == UNFY_NO)
  604. goto no;
  605. return stat;
  606. }
  607. /* swap temporarily if not no */
  608. SWAP(val, info->right);
  609. if ((stat = unfy_unify(info, rec)) == UNFY_NO) {
  610. info->rvar = info->rvar ? info->rvar : val;
  611. } else
  612. SWAP(val, info->right);
  613. return stat;
  614. no:
  615. info->rsn = UNFY_RSN_SELF;
  616. return stat;
  617. }
  618. static Unfy_stat
  619. unify_var_nonvar(Unfy_info *info, Unfy_recycle *rec)
  620. {
  621. Unfy_stat stat;
  622. SWAP(info->left, info->right);
  623. SWAP(info->lbind, info->rbind);
  624. stat = unify_nonvar_var(info, rec);
  625. SWAP(info->left, info->right);
  626. SWAP(info->lbind, info->rbind);
  627. SWAP(info->lvar, info->rvar);
  628. return stat;
  629. }
  630. static Unfy_stat
  631. unify_vars(Unfy_info *info, Unfy_recycle *rec)
  632. {
  633. Unfy_term *lval = unfy_bind_get(info->lbind, info->left->u.id);
  634. Unfy_term *rval = unfy_bind_get(info->rbind, info->right->u.id);
  635. Unfy_stat stat;
  636. if (!lval) {
  637. Unfy_term shared;
  638. if (rval) {
  639. if ((stat = bind_add(&info->lbind, &info->rbind,
  640. info->left->u.id,
  641. rval, rec)) == UNFY_NO)
  642. goto no;
  643. return stat;
  644. }
  645. /* create a new variable to be shared */
  646. unfy_term_init(&shared, UNFY_VAR, NULL);
  647. if ((stat = bind_add(&info->lbind, &info->rbind, info->left->u.id,
  648. &shared, rec)) == UNFY_NO)
  649. goto no;
  650. if (stat != UNFY_YES)
  651. return stat;
  652. if ((stat = bind_add(&info->rbind, &info->lbind,
  653. info->right->u.id, &shared,
  654. rec)) == UNFY_NO)
  655. goto no;
  656. return stat;
  657. }
  658. if (!rval) {
  659. if ((stat = bind_add(&info->rbind, &info->lbind,
  660. info->right->u.id, lval, rec)) == UNFY_NO)
  661. goto no;
  662. return stat;
  663. }
  664. if (lval->type == UNFY_VAR) {
  665. /* don't do extra work if same */
  666. if (rval->type == UNFY_VAR &&
  667. !rid_cmp(lval->u.id, rval->u.id))
  668. return UNFY_YES;
  669. if ((stat = bind_set(&info->lbind, &info->rbind,
  670. lval->u.id, rval, rec)) == UNFY_NO)
  671. goto no;
  672. return stat;
  673. }
  674. if (rval->type == UNFY_VAR) {
  675. if ((stat = bind_set(&info->rbind, &info->lbind,
  676. rval->u.id, lval, rec)) == UNFY_NO)
  677. goto no;
  678. return stat;
  679. }
  680. /* temporary swap if not no */
  681. SWAP(info->left, lval);
  682. SWAP(info->right, rval);
  683. if ((stat = unfy_unify(info, rec)) == UNFY_NO) {
  684. info->lvar = info->lvar ? info->lvar : lval;
  685. info->lvar = info->rvar ? info->rvar : rval;
  686. } else {
  687. SWAP(info->left, lval);
  688. SWAP(info->right, rval);
  689. }
  690. return stat;
  691. no:
  692. info->rsn = UNFY_RSN_SELF;
  693. return UNFY_NO;
  694. }
  695. static Unfy_stat
  696. unify_ignore(Unfy_info *info, Unfy_recycle *rec)
  697. {
  698. (void) info;
  699. (void) rec;
  700. return UNFY_YES;
  701. }
  702. Unfy_stat
  703. unfy_unify(Unfy_info *info, Unfy_recycle *rec)
  704. {
  705. typedef Unfy_stat (*Unfy_func)(Unfy_info *info, Unfy_recycle *rec);
  706. const Unfy_func table[5][5] = {
  707. [UNFY_CONST][UNFY_CONST] = unify_consts,
  708. [UNFY_CONST][UNFY_ORDER] = dont_unify,
  709. [UNFY_CONST][UNFY_IGN] = unify_ignore,
  710. [UNFY_CONST][UNFY_LIST] = dont_unify,
  711. [UNFY_CONST][UNFY_VAR] = unify_nonvar_var,
  712. [UNFY_ORDER][UNFY_CONST] = dont_unify,
  713. [UNFY_ORDER][UNFY_ORDER] = unify_orders,
  714. [UNFY_ORDER][UNFY_IGN] = unify_ignore,
  715. [UNFY_ORDER][UNFY_LIST] = dont_unify,
  716. [UNFY_ORDER][UNFY_VAR] = unify_nonvar_var,
  717. [UNFY_IGN] [UNFY_CONST] = unify_ignore,
  718. [UNFY_IGN] [UNFY_ORDER] = unify_ignore,
  719. [UNFY_IGN] [UNFY_IGN] = unify_ignore,
  720. [UNFY_IGN] [UNFY_LIST] = unify_ignore,
  721. [UNFY_IGN] [UNFY_VAR] = unify_ignore,
  722. [UNFY_LIST] [UNFY_CONST] = dont_unify,
  723. [UNFY_LIST] [UNFY_ORDER] = dont_unify,
  724. [UNFY_LIST] [UNFY_IGN] = unify_ignore,
  725. [UNFY_LIST] [UNFY_LIST] = unify_lists,
  726. [UNFY_LIST] [UNFY_VAR] = unify_nonvar_var,
  727. [UNFY_VAR] [UNFY_CONST] = unify_var_nonvar,
  728. [UNFY_VAR] [UNFY_ORDER] = unify_var_nonvar,
  729. [UNFY_VAR] [UNFY_IGN] = unify_ignore,
  730. [UNFY_VAR] [UNFY_LIST] = unify_var_nonvar,
  731. [UNFY_VAR] [UNFY_VAR] = unify_vars,
  732. };
  733. return table[info->left->type][info->right->type](info, rec);
  734. }
  735. void
  736. unfy_info_init(Unfy_info *info, Unfy_term *left, Unfy_term *right)
  737. {
  738. info->lbind = NULL;
  739. info->rbind = NULL;
  740. info->rsn = UNFY_RSN_OKAY;
  741. info->left = left;
  742. info->right = right;
  743. info->lvar = NULL;
  744. info->rvar = NULL;
  745. }
  746. void
  747. unfy_info_dispose(Unfy_info *info, Unfy_recycle *rec)
  748. {
  749. unfy_recycle_bind(rec, info->lbind);
  750. unfy_recycle_bind(rec, info->rbind);
  751. }