rls.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. /* This file is part of rls.
  2. *
  3. * Rls 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. * Rls 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 rls. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <rid.h>
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #define STYLE_9
  21. #include <unfy/unfy.h>
  22. #include "rls.h"
  23. /* utility code for binds */
  24. #define ARRAY_UNITS(array) (sizeof(array) / sizeof(*array))
  25. typedef struct {
  26. Rid var_ids[8];
  27. int id_cnt;
  28. void *up;
  29. } Binds_part;
  30. static int
  31. part_holds(const Binds_part *part, const Rid id)
  32. {
  33. for (; part; part = part->up)
  34. for (int i = 0; i < part->id_cnt; ++i)
  35. if (!rid_cmp(id, part->var_ids[i]))
  36. return 1;
  37. return 0;
  38. }
  39. /* uses more of stack over allocating memory, might want to rethink */
  40. static ssize_t
  41. max_binds_list(const Unfy_list *list, void *up)
  42. {
  43. ssize_t len = 0;
  44. Binds_part part = { .up = up, .id_cnt = 0 };
  45. for (; list; list = list->next) {
  46. const Unfy_term *term = list->term;
  47. ssize_t sub_len;
  48. switch (term->type) {
  49. case UNFY_CONST:
  50. case UNFY_ORDER:
  51. case UNFY_IGN:
  52. break;
  53. case UNFY_LIST:
  54. sub_len = max_binds_list(term->u.list, &part);
  55. if (sub_len < 0)
  56. return -1;
  57. len += sub_len;
  58. break;
  59. case UNFY_VAR:
  60. if (part_holds(&part, term->u.id))
  61. break;
  62. ++len;
  63. if (part.id_cnt <
  64. (ssize_t) ARRAY_UNITS(part.var_ids)) {
  65. rid_set(part.var_ids[part.id_cnt], term->u.id);
  66. ++part.id_cnt;
  67. break;
  68. }
  69. if ((sub_len = max_binds_list(list->next, &part)) < 0)
  70. return -1;
  71. return sub_len + len;
  72. }
  73. }
  74. return len;
  75. }
  76. static ssize_t
  77. max_binds(const Unfy_term *term)
  78. {
  79. switch (term->type) {
  80. case UNFY_IGN:
  81. case UNFY_CONST:
  82. case UNFY_ORDER:
  83. return 0;
  84. case UNFY_VAR:
  85. return 1;
  86. case UNFY_LIST:
  87. return max_binds_list(term->u.list, NULL);
  88. }
  89. /* this will never happen */
  90. return -1;
  91. }
  92. static ssize_t
  93. bind_len(const Unfy_bind *bind)
  94. {
  95. ssize_t len = 0;
  96. for (; bind; bind = bind->next, ++len);
  97. return len;
  98. }
  99. /* Main code */
  100. int
  101. rls_info_init(Rls_info *info, Unfy_term *term,
  102. Rls_rule *rules, Rls_recycle *rec)
  103. {
  104. info->nbind = NULL;
  105. info->term = term;
  106. if (unfy_term_revar(term, &info->nbind, &rec->unfy) < 0)
  107. return -1;
  108. if (info->nbind) {
  109. info->nterm = unfy_term_bind(term, info->nbind, &rec->unfy);
  110. if (!info->nterm)
  111. return -1;
  112. term = info->nterm;
  113. } else {
  114. info->nbind = NULL;
  115. info->nterm = NULL;
  116. }
  117. unfy_info_init(&info->unfy, term, rules ? rules->head : NULL);
  118. info->rule = rules;
  119. info->rsn = RLS_RSN_OKAY;
  120. return 0;
  121. }
  122. void
  123. rls_info_dispose(Rls_info *info, Rls_recycle *rec)
  124. {
  125. unfy_recycle_bind(&rec->unfy, info->nbind);
  126. unfy_recycle_term(&rec->unfy, info->nterm);
  127. unfy_info_dispose(&info->unfy, &rec->unfy);
  128. }
  129. void
  130. rls_info_change(Rls_info *info, Unfy_term *term,
  131. Rls_rule *rules, Rls_recycle *rec)
  132. {
  133. rls_info_dispose(info, rec);
  134. rls_info_init(info, term, rules, rec);
  135. }
  136. void
  137. rls_info_next(Rls_info *info, Rls_recycle *rec)
  138. {
  139. unfy_info_dispose(&info->unfy, &rec->unfy);
  140. info->unfy.lbind = info->unfy.rbind = NULL;
  141. info->rule = info->rule->next;
  142. info->unfy.left = info->nterm ? info->nterm : info->term;
  143. info->unfy.right = info->rule ? info->rule->head : NULL;
  144. }
  145. void
  146. rls_recycle_init(Rls_recycle *rec)
  147. {
  148. unfy_recycle_init(&rec->unfy);
  149. rec->rules = NULL;
  150. rec->srchs = NULL;
  151. }
  152. void
  153. rls_recycle_empty(Rls_recycle *rec)
  154. {
  155. unfy_recycle_empty(&rec->unfy);
  156. while (rec->rules) {
  157. Rls_rule *tmp = rec->rules;
  158. rec->rules = tmp->next;
  159. free(tmp);
  160. }
  161. rec->rules = NULL;
  162. while (rec->srchs) {
  163. Rls_srch *tmp = rec->srchs;
  164. rec->srchs = (void *) tmp->body;
  165. free(tmp);
  166. }
  167. rec->rules = NULL;
  168. }
  169. static Rls_rule *
  170. get_rule(Rls_recycle *rec)
  171. {
  172. Rls_rule *rule = rec->rules;
  173. if (!rule)
  174. return malloc(sizeof(*rule));
  175. rec->rules = rule->next;
  176. return rule;
  177. }
  178. void
  179. rls_recycle_rule(Rls_recycle *rec, Rls_rule *rule,
  180. Rls_dat_free dat_free, void *extra)
  181. {
  182. Rls_rule *end = rule;
  183. if (!rule)
  184. return;
  185. while (1) {
  186. unfy_recycle_term(&rec->unfy, end->head);
  187. if (dat_free)
  188. dat_free(end->dat, extra);
  189. if (!end->actable)
  190. unfy_recycle_list(&rec->unfy, end->u.body);
  191. if (!end->next)
  192. break;
  193. end = end->next;
  194. }
  195. end->next = rec->rules;
  196. rec->rules = rule;
  197. }
  198. static Rls_rule *
  199. rls_rule(const Rid id, Unfy_term *head, int actable, void *generic,
  200. int max, Rls_rule *next, void *dat, Rls_recycle *rec)
  201. {
  202. Rls_rule *rule;
  203. if (!(rule = get_rule(rec)))
  204. return NULL;
  205. rule->next = next;
  206. rule->head = head;
  207. rid_set(rule->id, id);
  208. rule->size = 0;
  209. rule->max_binds = max;
  210. rule->dat = dat;
  211. if ((rule->actable = actable)) {
  212. *(void **)(&rule->u.act) = generic;
  213. } else {
  214. Unfy_list *list = rule->u.body = generic;
  215. for (; list; list = list->next)
  216. ++rule->size;
  217. }
  218. return rule;
  219. }
  220. static int
  221. rls_rule_add_rule(Rls_rule **rule, const Rid id, Unfy_term *head,
  222. int actable, void *generic, void *dat, Rls_recycle *rec)
  223. {
  224. ssize_t lmax = max_binds(head);
  225. Rls_rule *here;
  226. if (lmax < 0)
  227. return -1;
  228. for (; *rule; rule = &(*rule)->next) {
  229. Unfy_info info;
  230. unfy_info_init(&info, head, (*rule)->head);
  231. switch (unfy_unify(&info, &rec->unfy)) {
  232. case UNFY_YES:
  233. if (bind_len(info.lbind) <= bind_len(info.rbind)) {
  234. unfy_info_dispose(&info, &rec->unfy);
  235. goto exit;
  236. }
  237. unfy_info_dispose(&info, &rec->unfy);
  238. break;
  239. case UNFY_NO:
  240. unfy_info_dispose(&info, &rec->unfy);
  241. if (lmax < (*rule)->max_binds)
  242. goto exit;
  243. break;
  244. case UNFY_ERR:
  245. unfy_info_dispose(&info, &rec->unfy);
  246. return -1;
  247. }
  248. }
  249. exit:
  250. if (!(here = rls_rule(id, head, actable, generic,
  251. lmax, *rule, dat, rec)))
  252. return -1;
  253. *rule = here;
  254. return 0;
  255. }
  256. int
  257. rls_rule_add(Rls_rule **rule, const Rid id, Unfy_term *head,
  258. Unfy_list *body, void *dat, Rls_recycle *rec)
  259. {
  260. return rls_rule_add_rule(rule, id, head, 0, body, dat, rec);
  261. }
  262. int
  263. rls_rule_add_actable(Rls_rule **rule, const Rid id, Unfy_term *head,
  264. Rls_act act, void *dat, Rls_recycle *rec)
  265. {
  266. return rls_rule_add_rule(rule, id, head, 1, *(void **)(&act),
  267. dat, rec);
  268. }
  269. Rls_dif
  270. rls_rule_same(Unfy_info *info, Rls_rule *left, Rls_rule *right,
  271. Rls_recycle *rec)
  272. {
  273. if (!left)
  274. return right ? RLS_DIF_NULL : RLS_DIF_SAME;
  275. if (!right)
  276. return RLS_DIF_NULL;
  277. unfy_info_init(info, left->head, right->head);
  278. switch (unfy_term_same(info, &rec->unfy)) {
  279. case UNFY_YES:
  280. break;
  281. case UNFY_NO:
  282. return RLS_DIF_HEAD;
  283. case UNFY_ERR:
  284. return RLS_DIF_ERR;
  285. }
  286. if (left->actable != right->actable) {
  287. return RLS_DIF_ACTABLE;
  288. } else if (left->actable) {
  289. if (left->u.act == right->u.act)
  290. goto same;
  291. return RLS_DIF_ACT;
  292. }
  293. /* setting left and right NULL to represent body lists
  294. since they are not stored in a term */
  295. info->left = NULL;
  296. info->right = NULL;
  297. switch (unfy_list_same(info, left->u.body,
  298. right->u.body, &rec->unfy)) {
  299. case UNFY_YES:
  300. break;
  301. case UNFY_NO:
  302. return RLS_DIF_BODY;
  303. case UNFY_ERR:
  304. return RLS_DIF_ERR;
  305. }
  306. same:
  307. unfy_info_dispose(info, &rec->unfy);
  308. return RLS_DIF_SAME;
  309. }
  310. Unfy_stat
  311. rls_rule_query(Rls_info *info, Rls_recycle *rec)
  312. {
  313. for (; info->rule; rls_info_next(info, rec)) {
  314. Unfy_stat stat = unfy_unify(&info->unfy, &rec->unfy);
  315. if (stat != UNFY_NO)
  316. return stat;
  317. /* info->rsn = RLS_RSN_UNFY; */
  318. /* return UNFY_NO; */
  319. }
  320. info->rsn = RLS_RSN_END;
  321. return UNFY_NO;
  322. }
  323. static Rls_srch *
  324. get_srch(Rls_recycle *rec)
  325. {
  326. Rls_srch *srch = rec->srchs;
  327. if (!srch)
  328. return malloc(sizeof(*srch));
  329. rec->srchs = (void *) srch->body;
  330. return srch;
  331. }
  332. static int
  333. srch_init(Rls_srch **srch_ref, Rls_srch *up, Unfy_term *term,
  334. Rls_rule *rules, uint16_t num, Rls_recycle *rec)
  335. {
  336. if (!(*srch_ref = get_srch(rec))) {
  337. unfy_recycle_term(&rec->unfy, term);
  338. return -1;
  339. }
  340. (*srch_ref)->up = up;
  341. (*srch_ref)->term = term;
  342. (*srch_ref)->rule = rules;
  343. (*srch_ref)->lbind = (*srch_ref)->rbind = NULL;
  344. (*srch_ref)->nbind = (*srch_ref)->fbind = NULL;
  345. (*srch_ref)->body = NULL;
  346. (*srch_ref)->num = num;
  347. return 0;
  348. }
  349. static void
  350. rec_srch_local(Rls_recycle *rec, Rls_srch *srch)
  351. {
  352. if (!srch)
  353. return;
  354. unfy_recycle_term(&rec->unfy, srch->term);
  355. unfy_recycle_bind(&rec->unfy, srch->lbind);
  356. unfy_recycle_bind(&rec->unfy, srch->rbind);
  357. unfy_recycle_bind(&rec->unfy, srch->nbind);
  358. unfy_recycle_bind(&rec->unfy, srch->fbind);
  359. if (srch->body)
  360. for (int i = 0; i < srch->rule->size; ++i)
  361. rec_srch_local(rec, srch->body[i]);
  362. free(srch->body);
  363. srch->body = (void *) rec->srchs;
  364. rec->srchs = srch;
  365. }
  366. void
  367. rls_recycle_srch(Rls_recycle *rec, Rls_srch *srch)
  368. {
  369. if (!srch)
  370. return;
  371. for (; srch->up; srch = srch->up);
  372. rec_srch_local(rec, srch);
  373. }
  374. static Unfy_term *
  375. rls_srch_bind(Rls_srch *srch, const Unfy_term *term, Rls_recycle *rec)
  376. {
  377. Unfy_term *bound;
  378. Rls_srch **body = srch->body;
  379. if (!(bound = unfy_term_bind(term, srch->rbind, &rec->unfy)))
  380. return NULL;
  381. for (int i = 0; i < srch->rule->size && body[i]; ++i) {
  382. if (unfy_term_bind_set(bound, body[i]->fbind, &rec->unfy) < 0) {
  383. unfy_recycle_term(&rec->unfy, bound);
  384. return NULL;
  385. }
  386. }
  387. return bound;
  388. }
  389. static int
  390. srch_fbind(Rls_srch *srch, Rls_recycle *rec)
  391. {
  392. Unfy_bind *fbind = NULL;
  393. Unfy_bind *nnbind = NULL;
  394. Unfy_bind *nbind = srch->nbind;
  395. for (; nbind; nbind = nbind->next) {
  396. Unfy_term *bound;
  397. Unfy_term *term;
  398. if (!(bound = unfy_term_bind(nbind->term, srch->lbind, &rec->unfy))) {
  399. unfy_recycle_bind(&rec->unfy, fbind);
  400. unfy_recycle_bind(&rec->unfy, nnbind);
  401. return -1;
  402. }
  403. term = rls_srch_bind(srch, bound, rec);
  404. unfy_recycle_term(&rec->unfy, bound);
  405. if (!term) {
  406. unfy_recycle_bind(&rec->unfy, fbind);
  407. unfy_recycle_bind(&rec->unfy, nnbind);
  408. return -1;
  409. }
  410. /* it remains unchanged */
  411. if (term->type == UNFY_VAR &&
  412. !rid_cmp(term->u.id, nbind->var_id)) {
  413. unfy_recycle_term(&rec->unfy, term);
  414. continue;
  415. }
  416. if (unfy_term_revar(term, &nnbind, &rec->unfy) < 0 ||
  417. unfy_term_bind_set(term, nnbind, &rec->unfy) < 0 ||
  418. unfy_bind(&fbind, nbind->var_id, term, &rec->unfy)) {
  419. unfy_recycle_term(&rec->unfy, term);
  420. unfy_recycle_bind(&rec->unfy, fbind);
  421. unfy_recycle_bind(&rec->unfy, nnbind);
  422. return -1;
  423. }
  424. }
  425. unfy_recycle_bind(&rec->unfy, nnbind);
  426. if (srch->fbind)
  427. unfy_recycle_bind(&rec->unfy, srch->fbind);
  428. srch->fbind = fbind;
  429. return 0;
  430. }
  431. static const Unfy_list *
  432. rule_get_pos(const Rls_rule *rule, int pos)
  433. {
  434. const Unfy_list *list = rule->u.body;
  435. for (; pos; --pos)
  436. list = list->next;
  437. return list;
  438. }
  439. static Rls_srch *
  440. srch_last(Rls_srch *srch)
  441. {
  442. /* down the the axioms */
  443. while (!srch->rule->actable && srch->body) {
  444. int i = 0;
  445. for (; i + 1 < srch->rule->size && srch->body[i + 1]; ++i);
  446. srch = srch->body[i];
  447. }
  448. return srch;
  449. }
  450. static inline Unfy_stat
  451. srch_from(Rls_srch *srch, Rls_info *info, Rls_recycle *rec)
  452. {
  453. unfy_recycle_bind(&rec->unfy, srch->lbind);
  454. unfy_recycle_bind(&rec->unfy, srch->rbind);
  455. unfy_recycle_bind(&rec->unfy, srch->nbind);
  456. srch->lbind = srch->rbind = srch->nbind = NULL;
  457. rls_info_init(info, srch->term, srch->rule, rec);
  458. switch (rls_rule_query(info, rec)) {
  459. case UNFY_YES:
  460. srch->rule = info->rule;
  461. srch->lbind = info->unfy.lbind;
  462. srch->rbind = info->unfy.rbind;
  463. srch->nbind = info->nbind;
  464. unfy_recycle_term(&rec->unfy, info->nterm);
  465. return UNFY_YES;
  466. case UNFY_NO:
  467. return UNFY_NO;
  468. case UNFY_ERR:
  469. break;
  470. }
  471. rls_info_dispose(info, rec);
  472. return UNFY_ERR;
  473. }
  474. static Unfy_stat
  475. init_body(Rls_srch **srch_ref, Rls_recycle *rec)
  476. {
  477. Unfy_term *bound;
  478. Rls_srch *srch = *srch_ref;
  479. if (!(srch->body = calloc(srch->rule->size, sizeof(Rls_srch *))) ||
  480. !(bound = rls_srch_bind(srch, srch->rule->u.body->term, rec)) ||
  481. srch_init(srch->body, srch, bound, NULL, srch->num + 1, rec) < 0)
  482. return UNFY_ERR;
  483. *srch_ref = srch->body[0];
  484. return UNFY_YES;
  485. }
  486. static Unfy_stat
  487. init_next(Rls_srch **srch_ref, Rls_srch *up, uint16_t num, Rls_recycle *rec);
  488. static Unfy_stat
  489. scale_up(Rls_srch **srch_ref, Rls_srch *up, uint16_t num, Rls_recycle *rec)
  490. {
  491. if (srch_fbind(up, rec) < 0)
  492. return UNFY_ERR;
  493. if (!up->up) {
  494. *srch_ref = up;
  495. return UNFY_YES;
  496. }
  497. return init_next(srch_ref, up->up, num, rec);
  498. }
  499. static Unfy_stat
  500. init_next(Rls_srch **srch_ref, Rls_srch *up, uint16_t num, Rls_recycle *rec)
  501. {
  502. int i = 0;
  503. const Unfy_list *list;
  504. Unfy_term *bound;
  505. for (; i < up->rule->size && up->body[i]; ++i);
  506. if (i == up->rule->size)
  507. return scale_up(srch_ref, up, num, rec);
  508. list = rule_get_pos(up->rule, i);
  509. if (!(bound = rls_srch_bind(up, list->term, rec)) ||
  510. srch_init(up->body + i, up, bound, NULL, num, rec) < 0)
  511. return UNFY_ERR;
  512. *srch_ref = up->body[i];
  513. return UNFY_YES;
  514. }
  515. static void
  516. step_no(Rls_srch **srch_ref, Rls_recycle *rec);
  517. static Unfy_stat
  518. step_yes(Rls_srch **srch_ref, void *extra, Rls_recycle *rec)
  519. {
  520. Rls_srch *srch = *srch_ref;
  521. if (!srch->rule->actable && srch->rule->u.body)
  522. return init_body(srch_ref, rec);
  523. if (srch_fbind(srch, rec) < 0)
  524. return UNFY_ERR;
  525. if (srch->rule->actable)
  526. switch (srch->rule->u.act(RLS_SRCH, srch, extra)) {
  527. case UNFY_YES:
  528. break;
  529. case UNFY_NO:
  530. /* I'm lazy, this should work */
  531. step_no(srch_ref, rec);
  532. return UNFY_NO;
  533. case UNFY_ERR:
  534. return UNFY_ERR;
  535. }
  536. if (srch->up)
  537. return init_next(srch_ref, srch->up, srch->num + 1, rec);
  538. return UNFY_YES;
  539. }
  540. static void
  541. step_no(Rls_srch **srch_ref, Rls_recycle *rec)
  542. {
  543. Rls_srch *up = (*srch_ref)->up;
  544. int i = 0;
  545. rec_srch_local(rec, *srch_ref);
  546. if (!up) {
  547. *srch_ref = NULL;
  548. return;
  549. }
  550. /* the previous srch should be last non NULL entry */
  551. for (; i + 1 < up->rule->size && up->body[i + 1]; ++i);
  552. if (!i) {
  553. free(up->body);
  554. up->body = NULL;
  555. *srch_ref = up;
  556. return;
  557. }
  558. up->body[i] = NULL;
  559. *srch_ref = srch_last(up->body[i - 1]);
  560. }
  561. static void
  562. srch_revert(Rls_srch *srch, Rls_recycle *rec)
  563. {
  564. if (srch->rule && srch->body)
  565. for (int i = 0; i < srch->rule->size; ++i)
  566. rec_srch_local(rec, srch->body[i]);
  567. free(srch->body);
  568. unfy_recycle_bind(&rec->unfy, srch->lbind);
  569. unfy_recycle_bind(&rec->unfy, srch->rbind);
  570. unfy_recycle_bind(&rec->unfy, srch->nbind);
  571. unfy_recycle_bind(&rec->unfy, srch->fbind);
  572. srch->rule = NULL;
  573. srch->body = NULL;
  574. srch->lbind = srch->rbind = srch->nbind = srch->fbind = NULL;
  575. }
  576. static Unfy_stat
  577. srch_step(Rls_srch **srch_ref, Rls_rule *rules, Rls_bend bend,
  578. Rls_info *info, void *extra, Rls_recycle *rec)
  579. {
  580. Unfy_stat stat = UNFY_NO; /* default value for bend returning NULL */
  581. if ((*srch_ref)->body)
  582. *srch_ref = srch_last(*srch_ref);
  583. if (bend && !(*srch_ref)->rule) {
  584. Rls_rule **tmp = bend((*srch_ref)->term, &stat, extra);
  585. if (!tmp)
  586. goto check;
  587. rules = *tmp;
  588. }
  589. (*srch_ref)->rule = (!(*srch_ref)->rule) ? rules : (*srch_ref)->rule->next;
  590. stat = srch_from(*srch_ref, info, rec);
  591. check:
  592. switch (stat) {
  593. case UNFY_YES:
  594. stat = step_yes(srch_ref, extra, rec);
  595. if (stat == UNFY_ERR)
  596. break;
  597. return stat;
  598. case UNFY_NO:
  599. step_no(srch_ref, rec);
  600. return UNFY_NO;
  601. case UNFY_ERR:
  602. break;
  603. }
  604. /* Safest way to recover from error, sure we'll lose some progress, but
  605. * it can be recovered in time.
  606. */
  607. srch_revert(*srch_ref, rec);
  608. return UNFY_ERR;
  609. }
  610. static Unfy_stat
  611. srch_loop(Rls_srch **srch_ref, Rls_rule *rules, int *limit,
  612. Rls_bend bend, Rls_info *info, void *extra, Rls_recycle *rec)
  613. {
  614. info->rsn = RLS_RSN_OKAY;
  615. while (1) {
  616. if (*limit > 0)
  617. --*limit;
  618. else if (!*limit) {
  619. if (info->rsn == RLS_RSN_OKAY) {
  620. /* makes safe for disposing info */
  621. info->rsn = RLS_RSN_LIMIT;
  622. info->nbind = NULL;
  623. info->nterm = NULL;
  624. info->unfy.lbind = info->unfy.rbind = NULL;
  625. }
  626. return UNFY_NO;
  627. }
  628. if (info->rsn != RLS_RSN_OKAY) {
  629. rls_info_dispose(info, rec);
  630. info->rsn = RLS_RSN_OKAY;
  631. }
  632. switch (srch_step(srch_ref, rules, bend,
  633. info, extra, rec)) {
  634. case UNFY_YES:
  635. if (!(*srch_ref)->up)
  636. return UNFY_YES;
  637. continue;
  638. case UNFY_NO:
  639. if (!(*srch_ref))
  640. return UNFY_NO;
  641. continue;
  642. case UNFY_ERR:
  643. return UNFY_ERR;
  644. }
  645. }
  646. return UNFY_ERR;
  647. }
  648. Unfy_stat
  649. rls_srch_limit(Rls_srch **srch_ref, Unfy_term *term, Rls_rule *rules,
  650. int *limit, Rls_bend bend, Rls_info *info, void *extra,
  651. Rls_recycle *rec)
  652. {
  653. if (!*srch_ref && srch_init(srch_ref, NULL, term, NULL, 0, rec) < 0)
  654. return UNFY_ERR;
  655. return srch_loop(srch_ref, rules, limit, bend, info, extra, rec);
  656. }
  657. Unfy_stat
  658. rls_srch(Rls_srch **srch_ref, Unfy_term *term, Rls_rule *rules,
  659. Rls_bend bend, Rls_info *info, void *extra, Rls_recycle *rec)
  660. {
  661. int limit = -1;
  662. return rls_srch_limit(srch_ref, term, rules, &limit,
  663. bend, info, extra, rec);
  664. }
  665. void
  666. rls_srch_next(Rls_srch **srch)
  667. {
  668. Rls_srch *tmp;
  669. if (!*srch)
  670. return;
  671. if ((*srch)->rule->size) {
  672. *srch = *(*srch)->body;
  673. return;
  674. }
  675. tmp = *srch;
  676. while ((*srch = (*srch)->up)) {
  677. uint16_t i = 0;
  678. for (; (*srch)->body[i] != tmp; ++i);
  679. if (i + 1 < (*srch)->rule->size) {
  680. *srch = (*srch)->body[i + 1];
  681. return;
  682. }
  683. tmp = *srch;
  684. }
  685. }
  686. int
  687. rls_srch_same_next(Rls_srch **left, Rls_srch **right)
  688. {
  689. Rls_srch *left_up;
  690. Rls_srch *right_up;
  691. if ((*left)->rule->size) {
  692. *left = *(*left)->body;
  693. *right = *(*right)->body;
  694. return 1;
  695. }
  696. for (;; *left = left_up, *right = right_up) {
  697. uint16_t i = 0;
  698. left_up = (*left)->up;
  699. right_up = (*right)->up;
  700. if (!left_up)
  701. return 0;
  702. for (; left_up->body[i] != *left; ++i);
  703. if (i + 1 < left_up->rule->size) {
  704. *left = left_up->body[i + 1];
  705. *right = right_up->body[i + 1];
  706. return 1;
  707. }
  708. }
  709. }
  710. Rls_dif
  711. rls_srch_same(Unfy_info *info, Rls_srch **left, Rls_srch **right,
  712. Rls_recycle *rec)
  713. {
  714. Rls_dif dif;
  715. if (!*left)
  716. return !*right ? RLS_DIF_SAME : RLS_DIF_NULL;
  717. if (!*right)
  718. return RLS_DIF_NULL;
  719. do {
  720. if ((dif = rls_rule_same(info, (*left)->rule,
  721. (*right)->rule, rec)) != RLS_DIF_SAME)
  722. return dif;
  723. } while (rls_srch_same_next(left, right));
  724. return RLS_DIF_SAME;
  725. }
  726. Unfy_stat
  727. rls_srch_run(Rls_srch *srch, void *extra)
  728. {
  729. Unfy_stat stat = UNFY_YES;
  730. if (!srch)
  731. return UNFY_YES;
  732. if (srch->rule->actable)
  733. return srch->rule->u.act(RLS_RUN, srch, extra);
  734. for (int i = 0; i < srch->rule->size; ++i)
  735. if ((stat = rls_srch_run(srch->body[i], extra)) != UNFY_YES)
  736. break;
  737. return stat;
  738. }