list.red 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. module list; % Define a list as a list of expressions in curly brackets.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1987 The RAND Corporation. All rights reserved.
  4. fluid '(orig!* posn!*);
  5. global '(cursym!* simpcount!* simplimit!*);
  6. % Add to system table.
  7. put('list,'tag,'list);
  8. put('list,'rtypefn,'quotelist);
  9. symbolic procedure quotelist u; 'list;
  10. % Parsing interface.
  11. symbolic procedure xreadlist;
  12. % Expects a list of expressions enclosed by {, }.
  13. % Used to allow expressions separated by ; - treated these as progn.
  14. begin scalar cursym,delim,lst;
  15. if scan() eq '!*rcbkt!* then <<scan(); return list 'list>>;
  16. a: lst := aconc(lst,xread1 'group);
  17. cursym := cursym!*;
  18. if cursym eq '!*semicol!*
  19. then symerr("Syntax error: semicolon in list",nil)
  20. else if scan() eq '!*rcbkt!* and cursym eq '!*comma!*
  21. then symerr("Syntax error: invalid comma in list",nil);
  22. if cursym eq '!*rcbkt!*
  23. then return % if delim eq '!*semicol!*
  24. % then 'progn . lst else
  25. 'list . lst
  26. else if null delim then delim := cursym;
  27. % else if not(delim eq cursym)
  28. % then symerr("Syntax error: mixed , and ; in list",nil);
  29. go to a
  30. end;
  31. put('!*lcbkt!*,'stat,'xreadlist);
  32. newtok '((!{) !*lcbkt!*);
  33. newtok '((!}) !*rcbkt!*);
  34. flag('(!*rcbkt!*),'delim);
  35. flag('(!*rcbkt!*),'nodel);
  36. % Evaluation interface.
  37. put('list,'evfn,'listeval);
  38. put('list,'simpfn,'simpiden); % This is a little kludgey, but allows
  39. % things like dms2deg to work.
  40. symbolic procedure getrlist u;
  41. if eqcar(u,'list) then cdr u
  42. else typerr(if eqcar(u,'!*sq) then prepsq cadr u else u,"list");
  43. symbolic procedure listeval(u,v);
  44. <<if (simpcount!* := simpcount!*+1)>simplimit!*
  45. then <<simpcount!* := 0;
  46. rerror(rlisp,18,"Simplification recursion too deep")>>;
  47. u := if atom u
  48. then listeval(if flagp(u,'share) then eval u
  49. else if x then cadr x else typerr(u,'list),v)
  50. where x=get(u,'avalue)
  51. else if car u eq 'list
  52. then makelist for each x in cdr u collect reval1(x,v)
  53. else ((if x then apply2(x,cdr u,v)
  54. else rerror(rlisp,19,"Illegal operation on lists"))
  55. where x = get(car u,'listfn));
  56. simpcount!* := simpcount!* - 1;
  57. u>>;
  58. symbolic procedure makelist u;
  59. % Make a list out of elements in u.
  60. 'list . u;
  61. % Length interface.
  62. put('list,'lengthfn,'lengthcdr);
  63. symbolic procedure lengthcdr u; length cdr u;
  64. % Printing interface.
  65. put('list,'prifn,'listpri);
  66. symbolic procedure listpri l;
  67. % This definition is basically that of INPRINT, except that it
  68. % decides when to split at the comma by looking at the size of
  69. % the argument.
  70. begin scalar orig,split,u;
  71. u := l;
  72. l := cdr l;
  73. prin2!* get('!*lcbkt!*,'prtch);
  74. % Do it this way so table can change.
  75. orig := orig!*;
  76. orig!* := if posn!*<18 then posn!* else orig!*+3;
  77. if null l then go to b;
  78. split := treesizep(l,40); % 40 is arbitrary choice.
  79. a: maprint(negnumberchk car l,0);
  80. l := cdr l;
  81. if null l then go to b;
  82. oprin '!*comma!*;
  83. if split then terpri!* t;
  84. go to a;
  85. b: prin2!* get('!*rcbkt!*,'prtch);
  86. % terpri!* nil;
  87. orig!* := orig;
  88. return u
  89. end;
  90. symbolic procedure treesizep(u,n);
  91. % true if u has recursively more pairs than n.
  92. treesizep1(u,n)=0;
  93. symbolic procedure treesizep1(u,n);
  94. if atom u then n - 1
  95. else if (n := treesizep1(car u,n))>0 then treesizep1(cdr u,n)
  96. else 0;
  97. % Definitions of operations on lists.
  98. symbolic procedure listeval0 u;
  99. begin scalar v;
  100. if (simpcount!* := simpcount!*+1)>simplimit!*
  101. then <<simpcount!* := 0;
  102. rerror(rlisp,20,"Simplification recursion too deep")>>;
  103. if idp u
  104. then if flagp(u,'share) then u := listeval0 eval u
  105. else if (v := get(u,'avalue)) and cadr v neq u
  106. then u := listeval0 cadr v;
  107. simpcount!* := simpcount!* - 1;
  108. return u
  109. end;
  110. % First, second, third and rest are designed so that only the relevant
  111. % elements need be fully evaluated.
  112. symbolic smacro procedure rlistp u; eqcar(u,'list);
  113. symbolic procedure rfirst u;
  114. begin scalar x;
  115. u := car u;
  116. % if null(getrtype(x := listeval0 u) eq 'list)
  117. % and null(getrtype(x := aeval u) eq 'list)
  118. if not rlistp(x := listeval0 u) and not rlistp(x := aeval u)
  119. then typerr(u,"list");
  120. if null cdr x then parterr(u,1) else return reval cadr x
  121. end;
  122. put('first,'psopfn,'rfirst);
  123. symbolic procedure parterr(u,v);
  124. msgpri("Expression",u,"does not have part",v,t);
  125. symbolic procedure rsecond u;
  126. begin scalar x;
  127. u := car u;
  128. if not rlistp(x := listeval0 u) and not rlistp(x := aeval u)
  129. then typerr(u,"list");
  130. if null cdr x or null cddr x then parterr(u,2)
  131. else return reval caddr x
  132. end;
  133. put('second,'psopfn,'rsecond);
  134. symbolic procedure rthird u;
  135. begin scalar x;
  136. u := car u;
  137. if not rlistp(x := listeval0 u) and not rlistp(x := aeval u)
  138. then typerr(u,"list");
  139. if null cdr x or null cddr x or null cdddr x then parterr(u,3)
  140. else return reval cadddr x
  141. end;
  142. put('third,'psopfn,'rthird);
  143. deflist('((first (lambda (x) 'yetunknowntype))
  144. (second (lambda (x) 'yetunknowntype))
  145. (third (lambda (x) 'yetunknowntype))
  146. (part (lambda (x) 'yetunknowntype))),
  147. 'rtypefn);
  148. symbolic procedure rrest u;
  149. begin scalar x;
  150. argnochk('cdr . u);
  151. u := car u;
  152. if not rlistp(x := listeval0 u) and not rlistp(x := aeval u)
  153. then typerr(u,"list");
  154. if null cdr x then typerr(u,"non-empty list")
  155. else return 'list . for each y in cddr x collect reval y
  156. end;
  157. put('rest,'psopfn,'rrest);
  158. deflist('((first 1) (second 1) (third 1) (rest 1)),'number!-of!-args);
  159. symbolic procedure rappend u;
  160. begin scalar x,y;
  161. argnochk('append . u);
  162. if null(getrtype(x := reval car u) eq 'list)
  163. then typerr(x,"list")
  164. else if null(getrtype(y := reval cadr u) eq 'list)
  165. then typerr(y,"list")
  166. else return 'list . append(cdr x,cdr y)
  167. end;
  168. put('append,'psopfn,'rappend);
  169. symbolic procedure rcons u;
  170. begin scalar x,y,z;
  171. argnochk('cons . u);
  172. if (y := getrtypeor(x := revlis u)) eq 'hvector
  173. then return if get('cons,'opmtch) and (z := opmtch('cons . x))
  174. then reval z
  175. else prepsq subs2 simpdot x
  176. else if not(getrtype cadr x eq 'list) then typerr(x,"list")
  177. else return 'list . car x . cdadr x
  178. end;
  179. put('cons,'psopfn,'rcons);
  180. symbolic procedure rreverse u;
  181. <<argnochk ('reverse . u);
  182. if null(getrtype(u := reval car u) eq 'list) then typerr(u,"list")
  183. else 'list . reverse cdr u>>;
  184. put('reverse,'psopfn,'rreverse);
  185. % Aggregate Property.
  186. symbolic procedure listmap(u,v);
  187. begin scalar x;
  188. x := cadr u;
  189. if null eqcar(x,'list) and null eqcar(x := reval1(x,v),'list)
  190. then typerr(cadr u,"list");
  191. return 'list
  192. . for each j in cdr x collect reval1(car u . j . cddr u,v)
  193. end;
  194. put('list,'aggregatefn,'listmap);
  195. % Sorting.
  196. fluid '(sortfcn!*);
  197. symbolic procedure listsort u;
  198. begin scalar l,n,w;
  199. if length u neq 2 then goto err;
  200. l:=cdr listeval(car u,nil);
  201. sortfcn!*:=cadr u;
  202. if(w:=get(sortfcn!*,'boolfn)) then sortfcn!*:=w;
  203. if null getd sortfcn!* or
  204. (n:=get(sortfcn!*,'number!-of!-args)) and n neq 2
  205. then goto err;
  206. return 'list.sort(l,w or
  207. function(lambda(x,y);
  208. boolvalue!* reval {sortfcn!*,mkquote x,mkquote y}));
  209. err: rederr "illegal call to list sort";
  210. end;
  211. put('sort,'psopfn,'listsort);
  212. endmodule;
  213. end;