PageRenderTime 64ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/src/list.d

https://github.com/ynd/clisp-branch--ynd-devel
D | 1943 lines | 1419 code | 136 blank | 388 comment | 201 complexity | 2304a816024b159a46a4ac6926c1aae6 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * List functions for CLISP
  3. * Bruno Haible 1990-2005
  4. * Marcus Daniels 8.4.1994
  5. * Sam Steingold 1999-2008
  6. * German comments and names translated into English: Reini Urban 2008-01
  7. */
  8. #include "lispbibl.c"
  9. /* (PROG1 (CONS STACK_1 STACK_0) skipSTACK(2))
  10. removes 2 objects from STACK
  11. can trigger GC */
  12. local inline maygc object cons_from_stack (void)
  13. {
  14. var object ret = allocate_cons();
  15. Cdr(ret) = popSTACK();
  16. Car(ret) = popSTACK();
  17. return ret;
  18. }
  19. /* UP: Copies a list
  20. copy_list(list)
  21. > list: List
  22. < result: Copy of the list
  23. can trigger GC */
  24. global maygc object copy_list (object old_list) {
  25. /* Method: (copy-list l) = (mapcar #'identity l), mapcar forwards */
  26. if (atomp(old_list))
  27. return old_list;
  28. else { /* List with at least one element */
  29. var object run;
  30. pushSTACK(old_list);
  31. {
  32. var object new_list = allocate_cons();
  33. run = STACK_0; /* run runs through the old list */
  34. Car(new_list) = Car(run);
  35. STACK_0 = new_list;
  36. pushSTACK(new_list);
  37. }
  38. /* Loop: STACK_1 is the whole copy, STACK_0 = LAST of it, */
  39. /* run = the correspondend Cons of the original list. */
  40. while ( run=Cdr(run), consp(run) ) {
  41. /* one more Cons */
  42. pushSTACK(run); /* save run */
  43. var object new_cons = allocate_cons(); /* allocate new Cons */
  44. run = popSTACK(); /* run back */
  45. Cdr(STACK_0) = new_cons; /* and put as CDR of the LAST */
  46. Car(new_cons) = Car(run); /* copy CAR */
  47. STACK_0 = new_cons; /* this is now the new LAST */
  48. }
  49. Cdr(popSTACK()) = run; /* keep same (CDR (LAST old_list)) */
  50. return popSTACK();
  51. }
  52. }
  53. /* UP: Reverses a list by copying
  54. reverse(list)
  55. > list: List (x1 ... xm)
  56. < result: reversed List (xm ... x1)
  57. can trigger GC */
  58. global maygc object reverse (object list) {
  59. pushSTACK(list); pushSTACK(NIL);
  60. while (!endp(list)) {
  61. /* Here is for r=1,...,m: */
  62. /* STACK_0 = (xr-1 ... x1), list = (xr ... xm) */
  63. STACK_1 = Cdr(list);
  64. /* Here is for r=1,...,m: */
  65. /* STACK_0 = (xr-1 ... x1), STACK_1 = (xr+1 ... xm) */
  66. pushSTACK(Car(list));
  67. {
  68. var object new_cons = allocate_cons();
  69. Car(new_cons) = popSTACK(); /* = xr */
  70. Cdr(new_cons) = STACK_0; /* = (xr-1 ... x1) */
  71. STACK_0 = new_cons; /* = (xr ... x1) */
  72. }
  73. list = STACK_1; /* list := (xr+1 ... xm) */
  74. }
  75. list = popSTACK(); skipSTACK(1); return list;
  76. }
  77. #if 0
  78. /* another possibility: */
  79. global object reverse (object list) {
  80. pushSTACK(list); pushSTACK(NIL);
  81. while (mconsp(STACK_1)) {
  82. var object new_cons = allocate_cons();
  83. var object old_cons = STACK_1;
  84. STACK_1 = Cdr(old_cons);
  85. Car(new_cons) = Car(old_cons);
  86. Cdr(new_cons) = STACK_0;
  87. STACK_0 = new_cons;
  88. }
  89. list = popSTACK(); skipSTACK(1); return list;
  90. }
  91. #endif
  92. /* UP: get the list length and the last atom
  93. > obj: object
  94. < len: list length
  95. < last: the last atom */
  96. global uintL llength1 (object list, object* last) {
  97. var uintL count = 0;
  98. while (consp(list)) {
  99. count++; list=Cdr(list);
  100. }
  101. if (last) *last = list;
  102. return count;
  103. }
  104. /* UP: Constructs a list with exactly len elements.
  105. make_list(len)
  106. > STACK_0: Initial value for all elements
  107. > uintL len: wanted list length
  108. < result: List with len elements
  109. can trigger GC */
  110. global maygc object make_list (uintL len) {
  111. pushSTACK(NIL);
  112. while (len--) {
  113. /* STACK_0 = old list, STACK_1 = initial value */
  114. var object new_cons = allocate_cons();
  115. Car(new_cons) = STACK_1; Cdr(new_cons) = STACK_0;
  116. STACK_0 = new_cons;
  117. }
  118. return popSTACK();
  119. }
  120. /* UP: Reverses a list in-place, destructively.
  121. nreverse(list)
  122. > list: List (x1 ... xm)
  123. < result: List (xm ... x1), EQ to the old */
  124. global object nreverse (object list) {
  125. /* Algorithm:
  126. (lambda (L)
  127. (cond ((atom L) L)
  128. ((atom (cdr L)) L)
  129. ((atom (cddr L)) (rotatef (car L) (cadr L)) L)
  130. (t (let ((L1 (cdr L)))
  131. (do ((L3 L1 (cdr L3))
  132. (L2 nil (rplacd L3 L2)))
  133. ((atom (cdr L3))
  134. (setf (cdr L) L2)
  135. (setf (cdr L1) L3)
  136. (rotatef (car L) (car L3))))
  137. L)))) */
  138. if (consp(list)) { /* (atom L) -> L */
  139. var object list3 = Cdr(list); /* L3 := (cdr L) */
  140. if (!endp(list3)) { /* (atom (cdr L)) -> L */
  141. if (!endp(Cdr(list3))) {
  142. var object list1 = list3; /* Begin with L1 = L3 = (cdr L) */
  143. var object list2 = NIL; /* and L2 = NIL */
  144. do {
  145. var object h = Cdr(list3); /* save (cdr L3), */
  146. Cdr(list3) = list2; /* replace by L2, */
  147. list2 = list3; /* L2 := old L3 */
  148. list3 = h; /* L3 := old (cdr L3) */
  149. } while (!endp(Cdr(list3))); /* (atom (cdr L3)) -> end */
  150. /* L3 is the last and L2 the last but one list Cons. */
  151. Cdr(list) = list2; /* (setf (cdr L) L2) */
  152. Cdr(list1) = list3; /* (setf (cdr L1) L3) */
  153. }
  154. /* exchange (car list) and (car list3): */
  155. var object h = Car(list);
  156. Car(list) = Car(list3);
  157. Car(list3) = h;
  158. }
  159. }
  160. return list;
  161. }
  162. /* UP: A0 := (nreconc A0 A1)
  163. nreconc(list,obj)
  164. > list: List
  165. > obj: Object
  166. < result: (nreconc A0 A1) */
  167. global object nreconc (object list, object obj) {
  168. if (!endp(list)) { /* (atom L) -> L */
  169. var object list3 = Cdr(list); /* L3 := (cdr L) */
  170. if (!endp(list3)) { /* (atom (cdr L)) -> L */
  171. if (!endp(Cdr(list3))) {
  172. var object list1 = list3; /* Begin with L1 = L3 = (cdr L) */
  173. var object list2 = NIL; /* and L2 = NIL */
  174. do {
  175. var object h = Cdr(list3); /* save (cdr L3), */
  176. Cdr(list3) = list2; /* replace by L2, */
  177. list2 = list3; /* L2 := old L3 */
  178. list3 = h; /* L3 := old (cdr L3) */
  179. } while (!endp(Cdr(list3))); /* (atom (cdr L3)) -> end */
  180. /* L3 is the last and L2 the last but one list Cons. */
  181. Cdr(list) = list2; /* (setf (cdr L) L2) */
  182. Cdr(list1) = list3; /* (setf (cdr L1) L3) */
  183. }
  184. /* exchange (car list) and (car list3): */
  185. {
  186. var object h = Car(list);
  187. Car(list) = Car(list3);
  188. Car(list3) = h;
  189. }
  190. Cdr(list3) = obj; /* (setf (cdr L3) O) */
  191. } else {
  192. Cdr(list) = obj;
  193. }
  194. return list;
  195. } else
  196. return obj;
  197. }
  198. /* UP: Construct (delete obj (the list list) :test #'EQ)
  199. deleteq(list,obj)
  200. Remove from list all elements EQ to obj.
  201. > obj: to be removed element
  202. > list: List
  203. < result: modified List */
  204. global object deleteq (object list, object obj) {
  205. var object list1 = list;
  206. var object list2 = list;
  207. while (!atomp(list2)) {
  208. /* Here is either list1=list2=list or (cdr list1) = list2. */
  209. if (eq(Car(list2),obj))
  210. /* Remove (car list2): */
  211. if (eq(list2,list)) {
  212. /* Still at the start of the list */
  213. list2 = list1 = list = Cdr(list2);
  214. } else {
  215. /* advanced the start of the list */
  216. Cdr(list1) = list2 = Cdr(list2);
  217. }
  218. else {
  219. /* Remove nothing, advance: */
  220. list1 = list2; list2 = Cdr(list2);
  221. }
  222. }
  223. return list;
  224. }
  225. /* UP: Returns (car obj), with type check */
  226. local object car (object obj) {
  227. if (consp(obj))
  228. return Car(obj);
  229. else if (nullp(obj))
  230. return obj;
  231. else
  232. error_list(obj);
  233. }
  234. /* UP: Returns (cdr obj), with type check */
  235. local object cdr (object obj) {
  236. if (consp(obj))
  237. return Cdr(obj);
  238. else if (nullp(obj))
  239. return obj;
  240. else
  241. error_list(obj);
  242. }
  243. LISPFUNNR(car,1)
  244. { /* (CAR list), CLTL p. 262 */
  245. VALUES1(car(popSTACK()));
  246. }
  247. LISPFUNNR(cdr,1)
  248. { /* (CDR list), CLTL p. 262 */
  249. VALUES1(cdr(popSTACK()));
  250. }
  251. LISPFUNNR(caar,1)
  252. { /* (CAAR list), CLTL p. 263 */
  253. VALUES1(car(car(popSTACK())));
  254. }
  255. LISPFUNNR(cadr,1)
  256. { /* (CADR list), CLTL p. 263 */
  257. VALUES1(car(cdr(popSTACK())));
  258. }
  259. LISPFUNNR(cdar,1)
  260. { /* (CDAR list), CLTL p. 263 */
  261. VALUES1(cdr(car(popSTACK())));
  262. }
  263. LISPFUNNR(cddr,1)
  264. { /* (CDDR list), CLTL p. 263 */
  265. VALUES1(cdr(cdr(popSTACK())));
  266. }
  267. LISPFUNNR(caaar,1)
  268. { /* (CAAAR list), CLTL p. 263 */
  269. VALUES1(car(car(car(popSTACK()))));
  270. }
  271. LISPFUNNR(caadr,1)
  272. { /* (CAADR list), CLTL p. 263 */
  273. VALUES1(car(car(cdr(popSTACK()))));
  274. }
  275. LISPFUNNR(cadar,1)
  276. { /* (CADAR list), CLTL p. 263 */
  277. VALUES1(car(cdr(car(popSTACK()))));
  278. }
  279. LISPFUNNR(caddr,1)
  280. { /* (CADDR list), CLTL p. 263 */
  281. VALUES1(car(cdr(cdr(popSTACK()))));
  282. }
  283. LISPFUNNR(cdaar,1)
  284. { /* (CDAAR list), CLTL p. 263 */
  285. VALUES1(cdr(car(car(popSTACK()))));
  286. }
  287. LISPFUNNR(cdadr,1)
  288. { /* (CDADR list), CLTL p. 263 */
  289. VALUES1(cdr(car(cdr(popSTACK()))));
  290. }
  291. LISPFUNNR(cddar,1)
  292. { /* (CDDAR list), CLTL p. 263 */
  293. VALUES1(cdr(cdr(car(popSTACK()))));
  294. }
  295. LISPFUNNR(cdddr,1)
  296. { /* (CDDDR list), CLTL p. 263 */
  297. VALUES1(cdr(cdr(cdr(popSTACK()))));
  298. }
  299. LISPFUNNR(caaaar,1)
  300. { /* (CAAAAR list), CLTL p. 263 */
  301. VALUES1(car(car(car(car(popSTACK())))));
  302. }
  303. LISPFUNNR(caaadr,1)
  304. { /* (CAAADR list), CLTL p. 263 */
  305. VALUES1(car(car(car(cdr(popSTACK())))));
  306. }
  307. LISPFUNNR(caadar,1)
  308. { /* (CAADAR list), CLTL p. 263 */
  309. VALUES1(car(car(cdr(car(popSTACK())))));
  310. }
  311. LISPFUNNR(caaddr,1)
  312. { /* (CAADDR list), CLTL p. 263 */
  313. VALUES1(car(car(cdr(cdr(popSTACK())))));
  314. }
  315. LISPFUNNR(cadaar,1)
  316. { /* (CADAAR list), CLTL p. 263 */
  317. VALUES1(car(cdr(car(car(popSTACK())))));
  318. }
  319. LISPFUNNR(cadadr,1)
  320. { /* (CADADR list), CLTL p. 263 */
  321. VALUES1(car(cdr(car(cdr(popSTACK())))));
  322. }
  323. LISPFUNNR(caddar,1)
  324. { /* (CADDAR list), CLTL p. 263 */
  325. VALUES1(car(cdr(cdr(car(popSTACK())))));
  326. }
  327. LISPFUNNR(cadddr,1)
  328. { /* (CADDDR list), CLTL p. 263 */
  329. VALUES1(car(cdr(cdr(cdr(popSTACK())))));
  330. }
  331. LISPFUNNR(cdaaar,1)
  332. { /* (CDAAAR list), CLTL p. 263 */
  333. VALUES1(cdr(car(car(car(popSTACK())))));
  334. }
  335. LISPFUNNR(cdaadr,1)
  336. { /* (CDAADR list), CLTL p. 263 */
  337. VALUES1(cdr(car(car(cdr(popSTACK())))));
  338. }
  339. LISPFUNNR(cdadar,1)
  340. { /* (CDADAR list), CLTL p. 263 */
  341. VALUES1(cdr(car(cdr(car(popSTACK())))));
  342. }
  343. LISPFUNNR(cdaddr,1)
  344. { /* (CDADDR list), CLTL p. 263 */
  345. VALUES1(cdr(car(cdr(cdr(popSTACK())))));
  346. }
  347. LISPFUNNR(cddaar,1)
  348. { /* (CDDAAR list), CLTL p. 263 */
  349. VALUES1(cdr(cdr(car(car(popSTACK())))));
  350. }
  351. LISPFUNNR(cddadr,1)
  352. { /* (CDDADR list), CLTL p. 263 */
  353. VALUES1(cdr(cdr(car(cdr(popSTACK())))));
  354. }
  355. LISPFUNNR(cdddar,1)
  356. { /* (CDDDAR list), CLTL p. 263 */
  357. VALUES1(cdr(cdr(cdr(car(popSTACK())))));
  358. }
  359. LISPFUNNR(cddddr,1)
  360. { /* (CDDDDR list), CLTL p. 263 */
  361. VALUES1(cdr(cdr(cdr(cdr(popSTACK())))));
  362. }
  363. LISPFUN(cons,seclass_no_se,2,0,norest,nokey,0,NIL)
  364. { /* (CONS obj1 obj2), CLTL p. 264 */
  365. VALUES1(cons_from_stack());
  366. }
  367. /* UP: Tests the equality of two trees.
  368. tree_equal(stackptr,pcall_test,arg1,arg2)
  369. > arg1,arg2: two trees
  370. > stackptr: Pointer to the stack
  371. > A5: Adress of a test function, which compares arg1 and arg2 and may access
  372. the :TEST/:TEST-NOT arguments in *(stackptr+1).L resp.
  373. *(stackprt+0).L
  374. < result: true if equal, otherwise false
  375. can trigger GC */
  376. local maygc bool tree_equal (const gcv_object_t* stackptr, funarg_t* pcall_test,
  377. object arg1, object arg2) {
  378. start:
  379. if (atomp(arg1))
  380. if (atomp(arg2))
  381. /* arg1 and arg2 both are atoms */
  382. return pcall_test(stackptr,arg1,arg2);
  383. else
  384. return false;
  385. else
  386. if (atomp(arg2))
  387. return false;
  388. else {
  389. /* arg1 and arg2 both are Cons */
  390. check_STACK(); check_SP();
  391. pushSTACK(Cdr(arg1)); pushSTACK(Cdr(arg2));
  392. if (tree_equal(stackptr,pcall_test,Car(arg1),Car(arg2))) { /* recursive on CARs */
  393. /* if equal, compare tail-recursively the CDRs */
  394. arg2 = popSTACK(); arg1 = popSTACK(); goto start;
  395. } else {
  396. skipSTACK(2); return false;
  397. }
  398. }
  399. }
  400. LISPFUN(tree_equal,seclass_default,2,0,norest,key,2, (kw(test),kw(test_not)) )
  401. { /* (TREE-EQUAL x y :test :test-not), CLTL p. 264 */
  402. var gcv_object_t* stackptr = &STACK_0;
  403. /* check :TEST/:TEST-NOT arguments: */
  404. var funarg_t* pcall_test = check_test_args(stackptr);
  405. VALUES_IF(tree_equal(stackptr,pcall_test,STACK_3,STACK_2));
  406. skipSTACK(4);
  407. }
  408. /* UP: check whether OBJ ends a proper list
  409. endp(obj)
  410. > obj: object
  411. < result: true if obj is the list end NIL,
  412. false if obj is a Cons.
  413. error otherwise */
  414. global bool endp (object obj) {
  415. if (consp(obj))
  416. return false;
  417. else if (nullp(obj))
  418. return true;
  419. else
  420. error_proper_list_dotted(TheSubr(subr_self)->name,obj);
  421. }
  422. LISPFUNNF(endp,1)
  423. { /* (ENDP object), CLTL p. 264 */
  424. VALUES_IF(endp(popSTACK()));
  425. }
  426. /* Finds the length of a possibly circular or dotted list.
  427. list_length(list,&dotted)
  428. > list: an object
  429. < result: the length (integer >= 0, or NIL for circular lists)
  430. < dotted: if non-circular, the last atom, i.e., the indicator whether the list
  431. is dotted
  432. can trigger GC */
  433. global maygc object list_length (object list, object *dottedp) {
  434. /* (defun list-length (list)
  435. (do ((n 0 (+ n 2))
  436. (fast list (cddr fast))
  437. (slow list (cdr slow)))
  438. (nil)
  439. (when (endp fast) (return n))
  440. (when (endp (cdr fast)) (return (1+ n)))
  441. (when (eq (cdr fast) slow) (return nil))))
  442. (see CLtL p 265) */
  443. var object fast = list;
  444. var object slow = fast;
  445. var uintL n = 0;
  446. while (consp(fast)) {
  447. fast = Cdr(fast); n++;
  448. if (atomp(fast))
  449. break;
  450. if (eq(fast,slow))
  451. return NIL;
  452. fast = Cdr(fast); n++;
  453. slow = Cdr(slow);
  454. }
  455. pushSTACK(fast);
  456. var object len = UL_to_I(n);
  457. *dottedp = popSTACK();
  458. return len;
  459. }
  460. LISPFUNNR(list_length,1)
  461. { /* (LIST-LENGTH list), CLTL p. 265 */
  462. var object tail = NIL;
  463. var object len = list_length(popSTACK(),&tail);
  464. if (nullp(tail))
  465. VALUES1(len);
  466. else
  467. error_proper_list_dotted(S(list_length),tail);
  468. }
  469. LISPFUNNR(list_length_dotted,1)
  470. { /* traverses the list just once, otherwise equivalent to
  471. (defun list-length-dotted (l)
  472. (let ((ll (list-length l)))
  473. (when ll (values ll (cdr (last l)))))) */
  474. var object tail = NIL;
  475. var object len = list_length(popSTACK(),&tail);
  476. if (nullp(len))
  477. VALUES1(NIL);
  478. else
  479. VALUES2(len,tail);
  480. }
  481. LISPFUNNR(list_length_proper,1)
  482. { /* traverses the list just once, otherwise equivalent to
  483. (defun list-length-proper (l)
  484. (if (proper-list-p l)
  485. (length l)
  486. (error ...))) */
  487. var object tail = NIL;
  488. var object len = list_length(STACK_0,&tail);
  489. if (!nullp(tail)) error_proper_list_dotted(S(list_length_proper),tail);
  490. if (nullp(len)) error_proper_list_circular(S(list_length_proper),STACK_0);
  491. VALUES1(len); skipSTACK(1);
  492. }
  493. LISPFUNNR(list_length_in_bounds_p,4)
  494. { /* (sys::list-length-in-bounds-p obj n m restp) tests whether obj, as a list,
  495. starts with at least n conses and is either a proper list with < m conses
  496. or (if restp) has at least m conses or (if not restp) is a proper list with
  497. exactly m conses. */
  498. if (!posfixnump(STACK_2)) error_posfixnum(STACK_2);
  499. if (!posfixnump(STACK_1)) error_posfixnum(STACK_1);
  500. var object obj = STACK_3;
  501. var uintV n = posfixnum_to_V(STACK_2);
  502. var uintV i;
  503. for (i = n; i > 0; i--) {
  504. if (!consp(obj)) goto no;
  505. obj = Cdr(obj);
  506. }
  507. { var uintV m = posfixnum_to_V(STACK_1);
  508. if (m < n) goto no;
  509. for (i = m-n; i > 0; i--) {
  510. if (!consp(obj)) {
  511. if (nullp(obj))
  512. break;
  513. else
  514. goto no;
  515. }
  516. obj = Cdr(obj);
  517. }
  518. }
  519. if (nullp(STACK_0) && !nullp(obj))
  520. goto no;
  521. VALUES1(T); skipSTACK(4); return;
  522. no:
  523. VALUES1(NIL); skipSTACK(4);
  524. }
  525. LISPFUN(proper_list_length_in_bounds_p,seclass_read,2,1,norest,nokey,0,NIL)
  526. { /* (sys::proper-list-length-in-bounds-p obj n) tests whether obj is a
  527. proper-list with at least n conses.
  528. (sys::proper-list-length-in-bounds-p obj n m) tests whether obj is a
  529. proper-list with at least n and at most m conses. */
  530. if (!posfixnump(STACK_1)) error_posfixnum(STACK_1);
  531. if (boundp(STACK_0) && !posfixnump(STACK_0)) error_posfixnum(STACK_0);
  532. var object tail = NIL;
  533. var object len = list_length(STACK_2,&tail);
  534. if (nullp(tail) && !nullp(len)) {
  535. var uintL l = I_to_UL(len);
  536. if ((posfixnum_to_V(STACK_1) <= l)
  537. && (!boundp(STACK_0) || (l <= posfixnum_to_V(STACK_0))))
  538. VALUES1(T);
  539. else
  540. VALUES1(NIL);
  541. } else
  542. VALUES1(NIL);
  543. skipSTACK(3);
  544. }
  545. /* proper_list_p(obj)
  546. returns true if obj is a proper list, i.e. a list which is neither dotted
  547. nor circular, i.e. a list which ends in NIL. */
  548. global bool proper_list_p (object obj) {
  549. var object fast = obj;
  550. var object slow = fast;
  551. while (consp(fast)) {
  552. fast = Cdr(fast);
  553. if (atomp(fast))
  554. break;
  555. if (eq(fast,slow))
  556. return false;
  557. fast = Cdr(fast);
  558. slow = Cdr(slow);
  559. }
  560. return nullp(fast);
  561. }
  562. /* We cannot have lists longer than 1<<32 for RAM reasons
  563. but we must accept arbitrary positive integers in NTH, LAST &c.
  564. Here we truncate large integers to ~0.
  565. can trigger GC */
  566. local maygc uintL get_integer_truncate (object number) {
  567. /* for speed, handle the most common case first */
  568. if (posfixnump(number)) {
  569. #if (intVsize>intLsize)
  570. if (posfixnum_to_V(number) >= vbitm(intLsize))
  571. return ~(uintL)0; /* most-positive-uintL */
  572. #endif
  573. return posfixnum_to_V(number);
  574. }
  575. number = check_pos_integer(number);
  576. if (uint32_p(number)) return I_to_UL(number);
  577. return ~(uintL)0; /* most-positive-uintL */
  578. }
  579. LISPFUNNR(nth,2)
  580. { /* (NTH integer list), CLTL p. 265 */
  581. var uintL count = get_integer_truncate(STACK_1);
  582. var object list = STACK_0;
  583. while (count--) { list = cdr(list); } /* count CDRs */
  584. VALUES1(car(list)); /* one CAR */
  585. skipSTACK(2);
  586. }
  587. LISPFUNNR(first,1)
  588. { /* (FIRST list), CLTL p. 266 */
  589. VALUES1(car(popSTACK()));
  590. }
  591. LISPFUNNR(second,1)
  592. { /* (SECOND list), CLTL p. 266 */
  593. VALUES1(car(cdr(popSTACK())));
  594. }
  595. LISPFUNNR(third,1)
  596. { /* (THIRD list), CLTL p. 266 */
  597. VALUES1(car(cdr(cdr(popSTACK()))));
  598. }
  599. LISPFUNNR(fourth,1)
  600. { /* (FOURTH list), CLTL p. 266 */
  601. VALUES1(car(cdr(cdr(cdr(popSTACK())))));
  602. }
  603. LISPFUNNR(fifth,1)
  604. { /* (FIFTH list), CLTL p. 266 */
  605. VALUES1(car(cdr(cdr(cdr(cdr(popSTACK()))))));
  606. }
  607. LISPFUNNR(sixth,1)
  608. { /* (SIXTH list), CLTL p. 266 */
  609. VALUES1(car(cdr(cdr(cdr(cdr(cdr(popSTACK())))))));
  610. }
  611. LISPFUNNR(seventh,1)
  612. { /* (SEVENTH list), CLTL p. 266 */
  613. VALUES1(car(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK()))))))));
  614. }
  615. LISPFUNNR(eighth,1)
  616. { /* (EIGHTH list), CLTL p. 266 */
  617. VALUES1(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK())))))))));
  618. }
  619. LISPFUNNR(ninth,1)
  620. { /* (NINTH list), CLTL p. 266 */
  621. VALUES1(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK()))))))))));
  622. }
  623. LISPFUNNR(tenth,1)
  624. { /* (TENTH list), CLTL p. 266 */
  625. VALUES1(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(popSTACK())))))))))));
  626. }
  627. LISPFUNNR(rest,1)
  628. { /* (REST list), CLTL p. 266 */
  629. VALUES1(cdr(popSTACK()));
  630. }
  631. LISPFUNNR(nthcdr,2)
  632. { /* (NTHCDR integer list), CLTL p. 267 */
  633. var uintL count = get_integer_truncate(STACK_1);
  634. var object list = STACK_0;
  635. while (count--) {
  636. if (consp(list))
  637. /* Walk list. */
  638. list = Cdr(list);
  639. else if (nullp(list))
  640. /* End of list reached. */
  641. break;
  642. else
  643. error_list(list);
  644. }
  645. VALUES1(list);
  646. skipSTACK(2);
  647. }
  648. /* (SYS::CONSES-P n object) determines whether the object is a list
  649. consisting of length n at least. Similar to
  650. (if (= n 0) t (consp (nthcdr (- n 1) object)))
  651. except that it is robust against dotted lists, or to
  652. (if (= n 0) t (and (listp object) (>= (length object) n)))
  653. except that it is robust against circular and dotted lists. */
  654. LISPFUNNR(conses_p,2) {
  655. var uintL count = get_integer_truncate(STACK_1);
  656. var object list = STACK_0;
  657. value1 = T;
  658. if (count > 0) {
  659. if (atomp(list))
  660. value1 = NIL;
  661. else
  662. for (; --count > 0;) {
  663. list = Cdr(list);
  664. if (atomp(list)) {
  665. value1 = NIL;
  666. break;
  667. }
  668. }
  669. }
  670. mv_count=1;
  671. skipSTACK(2);
  672. }
  673. /* Get a replacement for the circular list
  674. can trigger GC */
  675. local maygc object replace_circular_list (object list) {
  676. dynamic_bind(S(print_circle),T);
  677. pushSTACK(NIL); /* no PLACE */
  678. pushSTACK(list); pushSTACK(TheSubr(subr_self)->name);
  679. check_value(error_condition,GETTEXT("~S: ~S is a circular list"));
  680. dynamic_unbind(S(print_circle));
  681. return value1;
  682. }
  683. LISPFUN(last,seclass_read,1,1,norest,nokey,0,NIL)
  684. { /* (LAST list [n]), CLtL2 p. 416-417, dpANS p. 14-34
  685. (defun last (list &optional (n 1))
  686. (check-type n (integer 0 *))
  687. (check-type list list)
  688. (do ((l list (cdr l))
  689. (r list)
  690. (i 0 (+ i 1)))
  691. ((atom l) r)
  692. (when (>= i n) (pop r)))) */
  693. var object intarg = popSTACK();
  694. /* check optional integer argument: */
  695. var uintL count = (boundp(intarg) ? get_integer_truncate(intarg) : 1);
  696. var object list = check_list(popSTACK());
  697. /* Optimisation of the two most common cases count=1 and count=0: */
  698. switch (count) {
  699. case 0: { last_0_restart:
  700. var object slow = list;
  701. while (consp(list)) {
  702. list = Cdr(list);
  703. if (atomp(list)) break;
  704. if (eq(list,slow)) {
  705. list = check_list(replace_circular_list(list));
  706. goto last_0_restart;
  707. }
  708. list = Cdr(list);
  709. slow = Cdr(slow);
  710. }
  711. } break;
  712. case 1: { last_1_restart:
  713. var object list2;
  714. var object slow = list;
  715. if (consp(list)) {
  716. while (1) {
  717. /* list is a Cons. */
  718. list2 = Cdr(list); if (atomp(list2)) break; list = list2;
  719. if (eq(list,slow)) {
  720. list = check_list(replace_circular_list(list));
  721. goto last_1_restart;
  722. }
  723. list2 = Cdr(list); if (atomp(list2)) break; list = list2;
  724. slow = Cdr(slow);
  725. }
  726. }
  727. }
  728. break;
  729. default: { last_default_restart:
  730. var object list2 = list;
  731. var object slow = list;
  732. var uintL ii = count;
  733. do {
  734. if (atomp(list2))
  735. goto done;
  736. list2 = Cdr(list2);
  737. } while (--ii);
  738. while (consp(list2)) {
  739. list2 = Cdr(list2); list = Cdr(list); if (atomp(list2)) break;
  740. if (eq(list,slow)) {
  741. list = check_list(replace_circular_list(list));
  742. goto last_default_restart;
  743. }
  744. list2 = Cdr(list2); list = Cdr(list);
  745. }
  746. done: ;
  747. }
  748. break;
  749. }
  750. VALUES1(list);
  751. }
  752. /* UP: Constructs a list with given elements.
  753. listof(len)
  754. > uintC len: wanted list length
  755. > on STACK: len Objects, first at the top
  756. < result: list of these objects
  757. removes len elements from the STACK
  758. changes STACK, can trigger GC */
  759. global maygc object listof (uintC len) {
  760. pushSTACK(NIL); /* starting with empty list */
  761. /* Cons len times the arguments to the front of this list: */
  762. while (len--) {
  763. var object new_cons = allocate_cons();
  764. Cdr(new_cons) = popSTACK();
  765. Car(new_cons) = STACK_0;
  766. STACK_0 = new_cons;
  767. }
  768. return popSTACK();
  769. }
  770. LISPFUN(list,seclass_no_se,0,0,rest,nokey,0,NIL)
  771. { /* (LIST {object}), CLTL p. 267 */
  772. VALUES1(listof(argcount));
  773. }
  774. LISPFUN(liststar,seclass_no_se,1,0,rest,nokey,0,NIL)
  775. { /* (LIST* obj1 {object}), CLTL p. 267 */
  776. /* Former list already on the stack */
  777. /* Cons the argcount arguments to the front of this list: */
  778. while (argcount--) {
  779. var object new_cons = allocate_cons();
  780. Cdr(new_cons) = popSTACK(); /* next argument before */
  781. Car(new_cons) = STACK_0;
  782. STACK_0 = new_cons;
  783. }
  784. VALUES1(popSTACK());
  785. }
  786. LISPFUN(make_list,seclass_no_se,1,0,norest,key,1, (kw(initial_element)) )
  787. { /* (MAKE-LIST size :initial-element), CLTL p. 268 */
  788. if (!boundp(STACK_0)) /* check :initial-element */
  789. STACK_0 = NIL; /* default :initial-element is NIL */
  790. VALUES1(make_list(I_to_UL(check_uint32(STACK_1))));
  791. skipSTACK(2);
  792. }
  793. LISPFUN(append,seclass_read,0,0,rest,nokey,0,NIL)
  794. { /* (APPEND {list}), CLTL p. 268 */
  795. if (argcount==0) {
  796. VALUES1(NIL); /* no arguments -> return NIL as result */
  797. } else {
  798. /* Append arguments. Run the loop argcount-1 times: */
  799. while (--argcount) {
  800. /* STACK_0 = result list from right. */
  801. /* STACK_1 := (append STACK_1 STACK_0), increase STACK by 1: */
  802. var object list1;
  803. {
  804. var object list2 = popSTACK(); /* result list (from right) */
  805. list1 = STACK_0; /* Argument to be added to the front */
  806. STACK_0 = list2; /* stack resulting list */
  807. }
  808. /* list1 needs to be a list: */
  809. if (atomp(list1))
  810. if (nullp(list1))
  811. ; /* if list1=NIL: (append nil x) = x, do nothing */
  812. else
  813. error_list(list1);
  814. else {
  815. /* (append list1 STACK_0), and list1 is a Cons: */
  816. /* Copy list1 and keep last Cons: */
  817. var object run;
  818. pushSTACK(list1);
  819. {
  820. var object new_list = allocate_cons();
  821. run = STACK_0; /* run runs through the old list list1 */
  822. Car(new_list) = Car(run);
  823. STACK_0 = new_list;
  824. pushSTACK(new_list);
  825. }
  826. /* Loop: STACK_1 has the full copy, STACK_0 = LAST of it, */
  827. /* run = the corresponding Cons of the original list list1. */
  828. while ( run=Cdr(run), !endp(run) ) {
  829. /* one more Cons */
  830. pushSTACK(run); /* save run */
  831. var object new_cons = allocate_cons(); /* allocate new Cons */
  832. run = popSTACK(); /* put back run */
  833. Cdr(STACK_0) = new_cons; /* and add as CDR of the LAST */
  834. Car(new_cons) = Car(run); /* copy CAR */
  835. STACK_0 = new_cons; /* this is now the new LAST */
  836. }
  837. /* Copy ready. STACK_2 = current result list, */
  838. /* STACK_1 = copy of list1, STACK_0 = LAST of it. */
  839. run = popSTACK(); /* end of copy */
  840. list1 = popSTACK(); /* copy finished */
  841. /*if (!nullp(Cdr(run))) ????
  842. error_proper_list_dotted(TheSubr(subr_self)->name,Cdr(run));*/
  843. Cdr(run) = STACK_0; /* add result copy */
  844. STACK_0 = list1; /* and the is the new result list */
  845. }
  846. }
  847. VALUES1(popSTACK()); /* result list as value */
  848. }
  849. }
  850. LISPFUNNR(copy_list,1)
  851. { /* (COPY-LIST list), CLTL p. 268 */
  852. VALUES1(copy_list(check_list(popSTACK())));
  853. }
  854. /* UP: Copies an A-list
  855. copy_alist(alist)
  856. > alist: A-list
  857. < result: Copy of the A-list
  858. can trigger GC */
  859. local maygc object copy_alist (object alist) {
  860. /* Algorithm:
  861. Instead of
  862. (mapcar #'(lambda (x) (if (consp x) (cons (car x) (cdr x)) x)) l)
  863. the list is first copied via copy-list, then the conses among the top
  864. level elements of the copy are replaced with conses with same CAR and CDR. */
  865. alist = copy_list(alist);
  866. pushSTACK(alist); /* save result list */
  867. /* a-list runs through to the result list */
  868. while (!endp(alist)) {
  869. if (mconsp(Car(alist))) {
  870. pushSTACK(alist); /* save a-list */
  871. var object new_cons = allocate_cons(); /* new Cons */
  872. alist = popSTACK(); /* a-list back */
  873. {
  874. var object old_cons = Car(alist);
  875. Car(new_cons) = Car(old_cons); Cdr(new_cons) = Cdr(old_cons);
  876. }
  877. Car(alist) = new_cons;
  878. }
  879. alist = Cdr(alist);
  880. }
  881. return popSTACK();
  882. }
  883. LISPFUNNR(copy_alist,1) /* (COPY-ALIST alist), CLTL p. 268 */
  884. { VALUES1(copy_alist(popSTACK())); }
  885. /* UP: Copies a tree. */
  886. local object copy_tree (object tree) {
  887. if (atomp(tree))
  888. return tree; /* Return atom unchanged */
  889. else {
  890. check_STACK(); check_SP();
  891. pushSTACK(Cdr(tree)); /* Save CDR */
  892. {
  893. var object temp = copy_tree(Car(tree)); /* Copy the CAR recursively */
  894. tree = STACK_0;
  895. STACK_0 = temp; /* Save CAR copy */
  896. temp = copy_tree(tree); /* Copy the CDR recursively */
  897. pushSTACK(temp); /* Save CDR copy */
  898. }
  899. return cons_from_stack();
  900. }
  901. }
  902. LISPFUNNR(copy_tree,1) /* (COPY-TREE tree), CLTL p. 269 */
  903. { VALUES1(copy_tree(popSTACK())); }
  904. LISPFUNNR(revappend,2)
  905. { /* (REVAPPEND list object), CLTL p. 269 */
  906. while (!endp(STACK_1)) {
  907. var object new_cons = allocate_cons(); /* new Cons */
  908. Car(new_cons) = Car(STACK_1); Cdr(new_cons) = STACK_0; /* (cons (car list) object) */
  909. STACK_0 = new_cons; /* This is the new, longer object */
  910. STACK_1 = Cdr(STACK_1); /* Shorten list */
  911. }
  912. VALUES1(popSTACK());
  913. skipSTACK(1);
  914. }
  915. LISPFUN(nconc,seclass_default,0,0,rest,nokey,0,NIL)
  916. { /* (NCONC {list}), CLTL p. 269 */
  917. if (argcount==0) {
  918. VALUES1(NIL); /* no arguments -> return NIL as result */
  919. } else {
  920. /* Append arguments. Run the loop for argcount-1 times: */
  921. while (--argcount) {
  922. /* STACK_0 = current result list from right. */
  923. /* STACK_1 := (nconc STACK_1 STACK_0), increase STACK by 1: */
  924. if (matomp(STACK_1))
  925. if (nullp(STACK_1)) {
  926. STACK_1 = STACK_0; skipSTACK(1); /* result list stays, skip argument */
  927. } else
  928. error_list(STACK_1);
  929. else {
  930. /* Add result list to (cdr (last STACK_1)): */
  931. var object list1 = STACK_1;
  932. var object list2;
  933. while (1) {
  934. /* Here list1 is a Cons. */
  935. list2 = Cdr(list1);
  936. if (atomp(list2))
  937. break;
  938. list1 = list2;
  939. }
  940. /* list1 is the last Cons of the argument STACK_1 */
  941. Cdr(list1) = popSTACK(); /* Add current result list */
  942. /* STACK_0 = new result list */
  943. }
  944. }
  945. VALUES1(popSTACK());
  946. }
  947. }
  948. LISPFUNN(nreconc,2) /* (NRECONC list1 list2), CLTL p. 269 */
  949. {
  950. var object list1 = check_list(STACK_1);
  951. var object list2 = STACK_0; skipSTACK(2);
  952. VALUES1(nreconc(list1,list2));
  953. }
  954. LISPFUNN(list_nreverse,1) /* (SYS::LIST-NREVERSE list) */
  955. { /* as (NREVERSE list), if list is a list. */
  956. VALUES1(nreverse(popSTACK()));
  957. }
  958. /* check that the argument is a non-circular list and return its length
  959. can trigger GC */
  960. local inline maygc uintL check_list_length (gcv_object_t *list_) {
  961. while(1) {
  962. /* Give an error if the argument is not a list. (It's stupid to allow
  963. dotted lists of length > 0 but to forbid dotted lists of length 0,
  964. but that's how ANSI CL specifies it.) */
  965. if (!listp(*list_)) *list_ = check_list_replacement(*list_);
  966. var object dotted_p;
  967. var object llen = list_length(*list_,&dotted_p);
  968. if (!nullp(llen)) return I_to_UL(llen);
  969. *list_ = replace_circular_list(*list_);
  970. }
  971. }
  972. LISPFUN(butlast,seclass_read,1,1,norest,nokey,0,NIL)
  973. { /* (BUTLAST list [integer]), CLTL p. 271 */
  974. var object intarg = popSTACK();
  975. /* check optional integer argument: */
  976. var uintL count = (boundp(intarg) ? get_integer_truncate(intarg) : 1);
  977. var uintL len = check_list_length(&STACK_0); /* list length */
  978. if (len<=count) {
  979. VALUES1(NIL); skipSTACK(1); /* length(list)<=count -> return NIL */
  980. } else {
  981. var uintL new_len = len - count; /* >0 */
  982. /* Creates a copy of the first new_len conses of the list STACK_0: */
  983. var object new_list = make_list(new_len); /* allocate new list */
  984. /* Copy list elements one by one, until new_list is full: */
  985. var object new_run = new_list; /* runs through the new list */
  986. var object old_run = popSTACK(); /* runs through the old list */
  987. do {
  988. Car(new_run) = Car(old_run);
  989. old_run = Cdr(old_run); new_run = Cdr(new_run);
  990. } while (!atomp(new_run));
  991. VALUES1(new_list);
  992. }
  993. }
  994. LISPFUN(nbutlast,seclass_default,1,1,norest,nokey,0,NIL)
  995. { /* (NBUTLAST list [integer]), CLTL p. 271 */
  996. var object intarg = popSTACK();
  997. /* check optional integer argument: */
  998. var uintL count = (boundp(intarg) ? get_integer_truncate(intarg) : 1);
  999. var uintL len = check_list_length(&STACK_0); /* list length */
  1000. if (len<=count) {
  1001. VALUES1(NIL); skipSTACK(1); /* length(list)<=count -> return NIL */
  1002. } else {
  1003. var uintL new_len = len - count; /* >0 */
  1004. var object run = STACK_0; /* runs through the list */
  1005. /* take new_len-1 times the CDR and then set the CDR to NIL: */
  1006. while (--new_len) run = Cdr(run);
  1007. Cdr(run) = NIL;
  1008. VALUES1(popSTACK()); /* return list */
  1009. }
  1010. }
  1011. LISPFUNNR(ldiff,2)
  1012. { /* (LDIFF list sublist), CLTL p. 272 */
  1013. var object sublist = popSTACK();
  1014. /* Search where sublist begins in list: */
  1015. var uintL new_len = 0;
  1016. var bool found_p = false;
  1017. {
  1018. var object listr = STACK_0;
  1019. #ifndef X3J13_175
  1020. while (!((found_p = eql(listr,sublist)) || endp(listr))) {
  1021. listr = Cdr(listr); new_len++;
  1022. }
  1023. #else
  1024. if (!listp(listr))
  1025. error_list(listr);
  1026. while (!((found_p = eql(listr,sublist)) || atomp(listr))) {
  1027. listr = Cdr(listr); new_len++;
  1028. }
  1029. #endif
  1030. }
  1031. /* Return a copy of the first new_len conses of the list STACK_0: */
  1032. var object new_list = make_list(new_len); /* allocate new list */
  1033. /* Copy list elements one by one, until new_list is full: */
  1034. var object new_run = new_list; /* runs through the new list */
  1035. var object old_run = popSTACK(); /* runs through the old list */
  1036. if (consp(new_run)) while (1) { /* loop! */
  1037. Car(new_run) = Car(old_run);
  1038. if (atomp(Cdr(new_run))) {
  1039. if (!found_p)
  1040. Cdr(new_run) = Cdr(old_run);
  1041. break;
  1042. }
  1043. old_run = Cdr(old_run); new_run = Cdr(new_run);
  1044. }
  1045. VALUES1(new_list);
  1046. }
  1047. /* check_cons(obj)
  1048. > obj: an object
  1049. < result: a cons, either the same as obj or a replacement
  1050. can trigger GC */
  1051. local maygc object check_cons_replacement (object obj) {
  1052. do {
  1053. pushSTACK(NIL); /* no PLACE */
  1054. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  1055. pushSTACK(S(cons)); /* TYPE-ERROR slot EXPECTED-TYPE */
  1056. pushSTACK(obj); pushSTACK(TheSubr(subr_self)->name);
  1057. check_value(type_error,GETTEXT("~S: ~S is not a pair"));
  1058. obj = value1;
  1059. } while (!consp(obj));
  1060. return obj;
  1061. }
  1062. local inline maygc object check_cons (object obj) {
  1063. if (!consp(obj))
  1064. obj = check_cons_replacement(obj);
  1065. return obj;
  1066. }
  1067. LISPFUNN(rplaca,2) /* (RPLACA cons object), CLTL p. 272 */
  1068. {
  1069. var object arg1 = check_cons(STACK_1);
  1070. var object arg2 = STACK_0;
  1071. skipSTACK(2);
  1072. Car(arg1) = arg2;
  1073. VALUES1(arg1);
  1074. }
  1075. LISPFUNN(prplaca,2) /* (SYS::%RPLACA cons object) */
  1076. { /* like (RPLACA cons object), but return object as value */
  1077. var object arg1 = check_cons(STACK_1);
  1078. var object arg2 = STACK_0;
  1079. skipSTACK(2);
  1080. Car(arg1) = arg2;
  1081. VALUES1(arg2);
  1082. }
  1083. LISPFUNN(rplacd,2) /* (RPLACD cons object), CLTL p. 272 */
  1084. {
  1085. var object arg1 = check_cons(STACK_1);
  1086. var object arg2 = STACK_0;
  1087. skipSTACK(2);
  1088. Cdr(arg1) = arg2;
  1089. VALUES1(arg1);
  1090. }
  1091. LISPFUNN(prplacd,2) /* (SYS::%RPLACD cons object) */
  1092. { /* like (RPLACD cons object), but return object as value */
  1093. var object arg1 = check_cons(STACK_1);
  1094. var object arg2 = STACK_0;
  1095. skipSTACK(2);
  1096. Cdr(arg1) = arg2;
  1097. VALUES1(arg2);
  1098. }
  1099. /* (funcall TESTFUN ...) */
  1100. #define CALL_TEST(p) (*pcall_test)(p,*(p STACKop 3),value1)
  1101. /* UP: Replaces in the tree all elements x, which KEY passes the TESTFUNction,
  1102. by NEW. Construktively (copying).
  1103. subst(tree,stackptr,up_fun)
  1104. > tree: the Tree
  1105. > stackptr: *(stackptr-2) = NEW, *(stackptr-1) = KEY
  1106. > up_fun: TESTFUN = Adress of the test function,
  1107. called with same stackptr and with (KEY x) as argument.
  1108. Returns true or false.
  1109. < result: (evtl. newer) tree
  1110. can trigger GC */
  1111. local maygc object subst (object tree, gcv_object_t* stackptr,
  1112. funarg_t* pcall_test) {
  1113. /* First calculate (KEY tree) and call TESTFUN: */
  1114. pushSTACK(tree); /* save tree */
  1115. funcall_key(*(stackptr STACKop -1),tree); /* (KEY tree) */
  1116. if (CALL_TEST(stackptr)) { /* (funcall TESTFUN ...) */
  1117. /* Test ok */
  1118. skipSTACK(1); return *(stackptr STACKop -2); /* return NEW as value */
  1119. } else /* Test not ok */
  1120. if (matomp(STACK_0)) {
  1121. /* Argument is an atom -> keep it unchanged */
  1122. return popSTACK();
  1123. } else {
  1124. /* Argument is a Cons -> call SUBST recursively: */
  1125. check_STACK(); check_SP();
  1126. /* call recursively for the CDR: */
  1127. var object new_cdr = subst(Cdr(STACK_0),stackptr,pcall_test);
  1128. pushSTACK(new_cdr); /* Save CDR result */
  1129. /* call recursively for the CAR: */
  1130. var object new_car = subst(Car(STACK_1),stackptr,pcall_test);
  1131. if (eq(new_car,Car(STACK_1)) && eq(STACK_0,Cdr(STACK_1))) {
  1132. /* both unchanged */
  1133. skipSTACK(1); /* skip CDR result */
  1134. return popSTACK();
  1135. } else {
  1136. STACK_1 = new_car; /* save CAR result */
  1137. return cons_from_stack();
  1138. }
  1139. }
  1140. }
  1141. LISPFUN(subst,seclass_default,3,0,norest,key,3,
  1142. (kw(test),kw(test_not),kw(key)) )
  1143. { /* (SUBST new old tree :test :test-not :key), CLTL p. 273 */
  1144. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1145. var funarg_t* pcall_test = check_test_args(&STACK_1); /* :TEST/:TEST-NOT arguments on STACK_2,STACK_1 */
  1146. pushSTACK(STACK_5); /* newobj */
  1147. /* stack layout: new, old, tree, test, test_not, key, new. */
  1148. VALUES1(subst(STACK_4,&STACK_2,pcall_test)); /* do the substitution */
  1149. skipSTACK(7);
  1150. }
  1151. LISPFUN(subst_if,seclass_default,3,0,norest,key,1, (kw(key)) )
  1152. { /* (SUBST-IF new pred tree :key), CLTL p. 273 */
  1153. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1154. pushSTACK(STACK_3); /* newobj */
  1155. /* stack layout: new, pred, tree, key, new. */
  1156. VALUES1(subst(STACK_2,&STACK_2,&call_if)); /* do the substitution */
  1157. skipSTACK(5);
  1158. }
  1159. LISPFUN(subst_if_not,seclass_default,3,0,norest,key,1, (kw(key)) )
  1160. { /* (SUBST-IF-NOT new pred tree :key), CLTL p. 273 */
  1161. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1162. pushSTACK(STACK_3); /* newobj */
  1163. /* stack layout: new, pred, tree, key, new. */
  1164. VALUES1(subst(STACK_2,&STACK_2,&call_if_not)); /* do the substitution */
  1165. skipSTACK(5);
  1166. }
  1167. /* UP: Replaces in the tree all elements x, which KEY passes the TESTFUNction,
  1168. by NEW. Destructively (in-place).
  1169. nsubst(tree,stackptr,up_fun)
  1170. > tree: the Tree
  1171. > stackptr: *(stackptr-2) = NEW, *(stackptr-1) = KEY
  1172. > up_fun: TESTFUN = Adress of the test function,
  1173. called with same stackptr and with (KEY x) as argument.
  1174. Returns true or false.
  1175. < result: same tree CAR
  1176. can trigger GC */
  1177. local maygc object nsubst (object tree, gcv_object_t* stackptr,
  1178. funarg_t* pcall_test) {
  1179. /* First calculate (KEY tree) and call TESTFUN: */
  1180. pushSTACK(tree); /* save tree */
  1181. funcall_key(*(stackptr STACKop -1),tree); /* (KEY tree) */
  1182. if (CALL_TEST(stackptr)) { /* (funcall TESTFUN ...) */
  1183. /* Test ok */
  1184. skipSTACK(1); return *(stackptr STACKop -2); /* NEW as value */
  1185. } else { /* Test not ok */
  1186. if (mconsp(STACK_0)) {
  1187. /* Argument is a Cons -> call NSUBST recursively: */
  1188. check_STACK(); check_SP();
  1189. { /* call recursively for the CDR: */
  1190. var object modified_cdr = nsubst(Cdr(STACK_0),stackptr,pcall_test);
  1191. Cdr(STACK_0) = modified_cdr;
  1192. }
  1193. { /* call recursively for the CAR: */
  1194. var object modified_car = nsubst(Car(STACK_0),stackptr,pcall_test);
  1195. Car(STACK_0) = modified_car;
  1196. }
  1197. }
  1198. return popSTACK(); /* return original tree address */
  1199. }
  1200. }
  1201. LISPFUN(nsubst,seclass_default,3,0,norest,key,3,
  1202. (kw(test),kw(test_not),kw(key)) )
  1203. { /* (NSUBST new old tree :test :test-not :key), CLTL p. 274 */
  1204. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1205. var funarg_t* pcall_test = check_test_args(&STACK_1); /* :TEST/:TEST-NOT arguments on STACK_2,STACK_1 */
  1206. pushSTACK(STACK_5); /* newobj */
  1207. /* stack layout: new, old, tree, test, test_not, key, new. */
  1208. VALUES1(nsubst(STACK_4,&STACK_2,pcall_test)); /* do the substitution */
  1209. skipSTACK(7);
  1210. }
  1211. LISPFUN(nsubst_if,seclass_default,3,0,norest,key,1, (kw(key)) )
  1212. { /* (NSUBST-IF new pred tree :key), CLTL p. 274 */
  1213. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1214. pushSTACK(STACK_3); /* newobj */
  1215. /* stack layout: new, pred, tree, key, new. */
  1216. VALUES1(nsubst(STACK_2,&STACK_2,&call_if)); /* do the substitution */
  1217. skipSTACK(5);
  1218. }
  1219. LISPFUN(nsubst_if_not,seclass_default,3,0,norest,key,1, (kw(key)) )
  1220. { /* (NSUBST-IF-NOT new pred tree :key), CLTL p. 274 */
  1221. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1222. pushSTACK(STACK_3); /* newobj */
  1223. /* stack layout: new, pred, tree, key, new. */
  1224. VALUES1(nsubst(STACK_2,&STACK_2,&call_if_not)); /* do the substitution */
  1225. skipSTACK(5);
  1226. }
  1227. /* UP: return the first list element, whose CAR passed the TESTFUNction.
  1228. sublis_assoc(stackptr)
  1229. > *(stackptr+3) = alist
  1230. > stackptr: *(stackptr-1) = KEY
  1231. > *(stackptr-3) = TESTFUN = test function, called on each list element
  1232. (u . v) with the same stackptr and with (KEY x) and u as arguments.
  1233. returns true, when the test passes, false otherwise.
  1234. < return: list element (a CONS) or NIL
  1235. can trigger GC */
  1236. local maygc object sublis_assoc (gcv_object_t* stackptr)
  1237. {
  1238. var object alist = *(stackptr STACKop 3);
  1239. pushSTACK(alist); /* save the list ((u . v) ...) */
  1240. while (!endp(STACK_0)) {
  1241. /* How to treat atoms in the list?
  1242. a. One can ignore them.
  1243. b. One can signal an error on them.
  1244. c. One can signal an error only for non-NIL atoms.
  1245. Obviously (b) is best, because it provides the best possible
  1246. error checking. But CLtL2 and CLHS both contain a "note" that
  1247. suggests to some people that atoms are ignored, therefore I
  1248. assume that there is code outside which assumes this behaviour,
  1249. and we must not signal an error on it.
  1250. Note: To other people this note suggests that only NILs are
  1251. ignored, and they suggest (c). This is inconsistent with the
  1252. definition of "association list" in the CLHS glossary and with
  1253. the general use of alists as lookup tables.
  1254. Therefore we implement (a).
  1255. SDS 2003-03-08: I am changing the behavior to (c) because
  1256. it is more in line with the ASSOC behavior */
  1257. var object head = Car(STACK_0);
  1258. if (mconsp(head)) { /* skip atoms in the list */
  1259. /* test whether the 2-argument test function
  1260. *(stackptr-3) (an adress!), called on u and the
  1261. value in *(stackptr-2), returns true: */
  1262. var bool erg = /* 2-argument test function, called on (KEY x) and u */
  1263. (*(funarg_t*)TheMachineCode(*(stackptr STACKop -3)))
  1264. ( stackptr, *(stackptr STACKop -2), Car(head) );
  1265. if (erg) /* test passed ==> return x = (u . v) = (CAR alist) */
  1266. return Car(popSTACK());
  1267. /* test failed */
  1268. } else if (!nullp(head))
  1269. error_list(head);
  1270. STACK_0 = Cdr(STACK_0); /* tail recursion */
  1271. }
  1272. skipSTACK(1); /* forget alist */
  1273. /* reached list end ==> return NIL */
  1274. return NIL;
  1275. }
  1276. /* UP: Replaces in tree all x by its A-LIST representation (by ASSOC):
  1277. x is replaced by the first v, so that (u . v) is a member in ALIST and
  1278. (KEY x) and u pass the TESTFUNction. Constructively (copying).
  1279. sublis(tree,stackptr)
  1280. > tree: the Tree
  1281. > stackptr: *(stackptr-1) = KEY, *(stackptr+3) = ALIST,
  1282. *(stackptr-2) is free for (KEY x)
  1283. < result: (evtl. newer) Tree
  1284. can trigger GC */
  1285. local maygc object sublis (object tree, gcv_object_t* stackptr) {
  1286. /* First calculate (KEY tree) and call ASSOC: */
  1287. pushSTACK(tree); /* save tree */
  1288. funcall_key(*(stackptr STACKop -1),tree); /* (KEY tree) */
  1289. *(stackptr STACKop -2) = value1; /* save for sublis_assoc */
  1290. var object assoc_erg = sublis_assoc(stackptr);
  1291. if (consp(assoc_erg)) { /* Test ok */
  1292. skipSTACK(1); return Cdr(assoc_erg); /* (CDR (ASSOC ...)) as value */
  1293. } else /* Test not ok */
  1294. if (matomp(STACK_0)) {
  1295. /* Argument is an atom -> keep unchanged */
  1296. return popSTACK();
  1297. } else {
  1298. /* Argument is a Cons -> call SUBLIS recursively: */
  1299. check_STACK(); check_SP();
  1300. /* call recursively for the CDR: */
  1301. var object new_cdr = sublis(Cdr(STACK_0),stackptr);
  1302. pushSTACK(new_cdr); /* save CDR result */
  1303. /* call recursively for the CAR: */
  1304. var object new_car = sublis(Car(STACK_1),stackptr);
  1305. if (eq(new_car,Car(STACK_1)) && eq(STACK_0,Cdr(STACK_1))) {
  1306. /* both unchanged */
  1307. skipSTACK(1); /* skip CDR result */
  1308. return popSTACK();
  1309. } else {
  1310. STACK_1 = new_car; /* save CAR result */
  1311. return cons_from_stack();
  1312. }
  1313. }
  1314. }
  1315. LISPFUN(sublis,seclass_default,2,0,norest,key,3,
  1316. (kw(test),kw(test_not),kw(key)) )
  1317. { /* (SUBLIS alist tree :test :test-not :key), CLTL p. 274 */
  1318. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1319. var gcv_object_t* stackptr = &STACK_1;
  1320. var funarg_t* pcall_test = check_test_args(stackptr); /* Call with :TEST/:TEST-NOT arguments */
  1321. /* on STACK_2,STACK_1 arguments. Returns true or false. */
  1322. if (nullp(STACK_4)) { /* shortcut: nothing to do if alist = () */
  1323. VALUES1(STACK_3);
  1324. skipSTACK(5);
  1325. } else {
  1326. pushSTACK(NIL); /* Dummy */
  1327. pushSTACK(make_machine_code(pcall_test)); /* Testfunction, because of Typeinfo=machine_type GC-safe! */
  1328. /* stack layout: alist, tree, test, test_not, key, dummy, pcall_test. */
  1329. VALUES1(sublis(STACK_5,stackptr)); /* do the substitution */
  1330. skipSTACK(7);
  1331. }
  1332. }
  1333. /* UP: Replaces in tree all x by its A-LIST representation (by ASSOC):
  1334. x is replaced by the first v, so that (u . v) is a member in ALIST and
  1335. (KEY x) and u pass the TESTFUNction. Destructively (in-place).
  1336. sublis(tree,stackptr)
  1337. > tree: the Tree
  1338. > stackptr: *(stackptr-1) = KEY, *(stackptr+3) = ALIST,
  1339. *(stackptr-2) is free for (KEY x)
  1340. < result: same Tree CAR
  1341. can trigger GC */
  1342. local maygc object nsublis (object tree, gcv_object_t* stackptr) {
  1343. /* First calculate (KEY tree) and call ASSOC: */
  1344. pushSTACK(tree); /* save tree */
  1345. funcall_key(*(stackptr STACKop -1),tree); /* (KEY tree) */
  1346. *(stackptr STACKop -2) = value1; /* save for sublis_assoc */
  1347. var object assoc_erg = sublis_assoc(stackptr);
  1348. if (consp(assoc_erg)) { /* Test ok */
  1349. skipSTACK(1); return Cdr(assoc_erg); /* (CDR (ASSOC ...)) as value */
  1350. } else { /* Test not ok */
  1351. if (mconsp(STACK_0)) {
  1352. /* Argument is a Cons -> call NSUBLIS recursively: */
  1353. check_STACK(); check_SP();
  1354. { /* call recursively for the CDR: */
  1355. var object modified_cdr = nsublis(Cdr(STACK_0),stackptr);
  1356. Cdr(STACK_0) = modified_cdr;
  1357. }
  1358. { /* call recursively for the CAR: */
  1359. var object modified_car = nsublis(Car(STACK_0),stackptr);
  1360. Car(STACK_0) = modified_car;
  1361. }
  1362. }
  1363. return popSTACK(); /* return original tree address */
  1364. }
  1365. }
  1366. LISPFUN(nsublis,seclass_default,2,0,norest,key,3,
  1367. (kw(test),kw(test_not),kw(key)) )
  1368. { /* (NSUBLIS alist tree :test :test-not :key), CLTL p. 275 */
  1369. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1370. var gcv_object_t* stackptr = &STACK_1;
  1371. var funarg_t* pcall_test = check_test_args(stackptr); /* Call with :TEST/:TEST-NOT arguments */
  1372. /* on STACK_2,STACK_1 arguments. Returns true or false. */
  1373. if (nullp(STACK_4)) { /* shortcut: nothing to do if alist = () */
  1374. VALUES1(STACK_3);
  1375. skipSTACK(5);
  1376. } else {
  1377. pushSTACK(NIL); /* Dummy */
  1378. pushSTACK(make_machine_code(pcall_test)); /* Testfunction, because of Typeinfo=machine_type GC-safe! */
  1379. /* Stackaufbau: alist, tree, test, test_not, key, dummy, pcall_test. */
  1380. VALUES1(nsublis(STACK_5,stackptr)); /* do the substitution */
  1381. skipSTACK(7);
  1382. }
  1383. }
  1384. /* UP: find OBJ in LIS: (MEMBER OBJ LIS :TEST #'EQ) */
  1385. global object memq (const object obj, const object lis) {
  1386. var object l = lis;
  1387. while (consp(l)) {
  1388. if (eq(Car(l),obj)) return l;
  1389. l = Cdr(l);
  1390. }
  1391. if (!nullp(l))
  1392. error_proper_list_dotted(TheSubr(subr_self)->name,l);
  1393. return NIL;
  1394. }
  1395. /* (SYS::MEMQ OBJECT LIST) == (MEMBER OBJECT LIST :TEST #'EQ) */
  1396. LISPFUNNR(memq,2) {
  1397. var object lis = popSTACK();
  1398. var object obj = popSTACK();
  1399. VALUES1(memq(obj,lis));
  1400. }
  1401. /* UP: Returns the rest of the list starting with the list element,
  1402. which satisfies the TESTFUNction.
  1403. member(list,stackptr,up_fun)
  1404. > list: List
  1405. > stackptr: *(stackptr-1) = KEY
  1406. > up_fun: TESTFUN = Address of the test function,
  1407. Called with same stackptr and with (KEY x) as argument.
  1408. Returns true or false.
  1409. < result: rest of list
  1410. can trigger GC */
  1411. local maygc object member (object list, gcv_object_t* stackptr,
  1412. funarg_t* pcall_test) {
  1413. while (!endp(list)) {
  1414. pushSTACK(list); /* save rest of list */
  1415. funcall_key(*(stackptr STACKop -1),Car(list)); /* (KEY x) */
  1416. {
  1417. var bool erg = CALL_TEST(stackptr); /* (funcall TESTFUN ...) */
  1418. list = popSTACK();
  1419. if (erg)
  1420. return list; /* Test ok -> list as result */
  1421. }
  1422. /* Test not ok -> call (member ... (cdr list)): */
  1423. list = Cdr(list); /* tail-end-recursively */
  1424. }
  1425. return list; /* NIL as result */
  1426. }
  1427. LISPFUN(member,seclass_default,2,0,norest,key,3,
  1428. (kw(test),kw(test_not),kw(key)) )
  1429. { /* (MEMBER item list :test :test-not :key), CLTL p. 275 */
  1430. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1431. var funarg_t* pcall_test = check_test_args(&STACK_1); /* :TEST/:TEST-NOT arguments on STACK_2,STACK_1 */
  1432. VALUES1(member(STACK_3,&STACK_1,pcall_test)); /* do the search */
  1433. skipSTACK(5);
  1434. }
  1435. LISPFUN(member_if,seclass_default,2,0,norest,key,1, (kw(key)) )
  1436. { /* (MEMBER-IF pred list :key), CLTL p. 275 */
  1437. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1438. VALUES1(member(STACK_1,&STACK_1,&call_if)); /* do the search */
  1439. skipSTACK(3);
  1440. }
  1441. LISPFUN(member_if_not,seclass_default,2,0,norest,key,1, (kw(key)) )
  1442. { /* (MEMBER-IF-NOT pred list :key), CLTL p. 275 */
  1443. check_key_arg(&STACK_0); /* :KEY argument on STACK_0 */
  1444. VALUES1(member(STACK_1,&STACK_1,&call_if_not)); /* do the search */
  1445. skipSTACK(3);
  1446. }
  1447. LISPFUNNR(tailp,2) /* (TAILP sublist list), CLTL p. 275 */
  1448. #ifndef X3J13_175
  1449. /* (defun tailp (sublist list)
  1450. (do ((l list (rest l)))
  1451. ((endp l) (null sublist))
  1452. (when (eq l sublist) (return t)))) */
  1453. #else
  1454. /* (defun tailp (sublist list)
  1455. (loop
  1456. (when (eql sublist list) (return t))
  1457. (when (atom list) (return nil))
  1458. (setq list (cdr list)))) */
  1459. #endif
  1460. {
  1461. var object list = popSTACK();
  1462. var object sublist = popSTACK();
  1463. #ifndef X3J13_175
  1464. while (!endp(list)) {
  1465. if (eq(list,sublist))
  1466. goto yes;
  1467. list = Cdr(list);
  1468. }
  1469. if (nullp(sublist))
  1470. goto yes;
  1471. #else
  1472. while (1) {
  1473. if (eql(list,sublist))
  1474. goto yes;
  1475. if (atomp(list))
  1476. break;
  1477. list = Cdr(list);
  1478. }
  1479. #endif
  1480. VALUES1(NIL); return; /* NIL as value */
  1481. yes:
  1482. VALUES1(T); return; /* T as value */
  1483. }
  1484. LISPFUN(adjoin,seclass_defa

Large files files are truncated, but you can click here to view the full file