alist.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /* Copyright 1995-2001,2004,2006,2008,2010-2011,2018
  2. Free Software Foundation, Inc.
  3. This file is part of Guile.
  4. Guile is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Guile is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with Guile. If not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include <config.h>
  17. #endif
  18. #include "boolean.h"
  19. #include "eq.h"
  20. #include "gsubr.h"
  21. #include "list.h"
  22. #include "numbers.h"
  23. #include "pairs.h"
  24. #include "alist.h"
  25. SCM_DEFINE (scm_acons, "acons", 3, 0, 0,
  26. (SCM key, SCM value, SCM alist),
  27. "Add a new key-value pair to @var{alist}. A new pair is\n"
  28. "created whose car is @var{key} and whose cdr is @var{value}, and the\n"
  29. "pair is consed onto @var{alist}, and the new list is returned. This\n"
  30. "function is @emph{not} destructive; @var{alist} is not modified.")
  31. #define FUNC_NAME s_scm_acons
  32. {
  33. return scm_cons (scm_cons (key, value), alist);
  34. }
  35. #undef FUNC_NAME
  36. SCM_DEFINE (scm_sloppy_assq, "sloppy-assq", 2, 0, 0,
  37. (SCM key, SCM alist),
  38. "Behaves like @code{assq} but does not do any error checking.\n"
  39. "Recommended only for use in Guile internals.")
  40. #define FUNC_NAME s_scm_sloppy_assq
  41. {
  42. for (; scm_is_pair (alist); alist = SCM_CDR (alist))
  43. {
  44. SCM tmp = SCM_CAR (alist);
  45. if (scm_is_pair (tmp) && scm_is_eq (SCM_CAR (tmp), key))
  46. return tmp;
  47. }
  48. return SCM_BOOL_F;
  49. }
  50. #undef FUNC_NAME
  51. SCM_DEFINE (scm_sloppy_assv, "sloppy-assv", 2, 0, 0,
  52. (SCM key, SCM alist),
  53. "Behaves like @code{assv} but does not do any error checking.\n"
  54. "Recommended only for use in Guile internals.")
  55. #define FUNC_NAME s_scm_sloppy_assv
  56. {
  57. /* In Guile, `assv' is the same as `assq' for keys of all types except
  58. numbers. */
  59. if (!SCM_NUMP (key))
  60. return scm_sloppy_assq (key, alist);
  61. for (; scm_is_pair (alist); alist = SCM_CDR (alist))
  62. {
  63. SCM tmp = SCM_CAR (alist);
  64. if (scm_is_pair (tmp)
  65. && scm_is_true (scm_eqv_p (SCM_CAR (tmp), key)))
  66. return tmp;
  67. }
  68. return SCM_BOOL_F;
  69. }
  70. #undef FUNC_NAME
  71. SCM_DEFINE (scm_sloppy_assoc, "sloppy-assoc", 2, 0, 0,
  72. (SCM key, SCM alist),
  73. "Behaves like @code{assoc} but does not do any error checking.\n"
  74. "Recommended only for use in Guile internals.")
  75. #define FUNC_NAME s_scm_sloppy_assoc
  76. {
  77. /* Immediate values can be checked using `eq?'. */
  78. if (SCM_IMP (key))
  79. return scm_sloppy_assq (key, alist);
  80. for (; scm_is_pair (alist); alist = SCM_CDR (alist))
  81. {
  82. SCM tmp = SCM_CAR (alist);
  83. if (scm_is_pair (tmp)
  84. && scm_is_true (scm_equal_p (SCM_CAR (tmp), key)))
  85. return tmp;
  86. }
  87. return SCM_BOOL_F;
  88. }
  89. #undef FUNC_NAME
  90. SCM_DEFINE (scm_assq, "assq", 2, 0, 0,
  91. (SCM key, SCM alist),
  92. "@deffnx {Scheme Procedure} assv key alist\n"
  93. "@deffnx {Scheme Procedure} assoc key alist\n"
  94. "Fetch the entry in @var{alist} that is associated with @var{key}. To\n"
  95. "decide whether the argument @var{key} matches a particular entry in\n"
  96. "@var{alist}, @code{assq} compares keys with @code{eq?}, @code{assv}\n"
  97. "uses @code{eqv?} and @code{assoc} uses @code{equal?}. If @var{key}\n"
  98. "cannot be found in @var{alist} (according to whichever equality\n"
  99. "predicate is in use), then return @code{#f}. These functions\n"
  100. "return the entire alist entry found (i.e. both the key and the value).")
  101. #define FUNC_NAME s_scm_assq
  102. {
  103. SCM ls = alist;
  104. for(; scm_is_pair (ls); ls = SCM_CDR (ls))
  105. {
  106. SCM tmp = SCM_CAR (ls);
  107. SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
  108. "association list");
  109. if (scm_is_eq (SCM_CAR (tmp), key))
  110. return tmp;
  111. }
  112. SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
  113. "association list");
  114. return SCM_BOOL_F;
  115. }
  116. #undef FUNC_NAME
  117. SCM_DEFINE (scm_assv, "assv", 2, 0, 0,
  118. (SCM key, SCM alist),
  119. "Behaves like @code{assq} but uses @code{eqv?} for key comparison.")
  120. #define FUNC_NAME s_scm_assv
  121. {
  122. SCM ls = alist;
  123. /* In Guile, `assv' is the same as `assq' for keys of all types except
  124. numbers. */
  125. if (!SCM_NUMP (key))
  126. return scm_assq (key, alist);
  127. for(; scm_is_pair (ls); ls = SCM_CDR (ls))
  128. {
  129. SCM tmp = SCM_CAR (ls);
  130. SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
  131. "association list");
  132. if (scm_is_true (scm_eqv_p (SCM_CAR (tmp), key)))
  133. return tmp;
  134. }
  135. SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
  136. "association list");
  137. return SCM_BOOL_F;
  138. }
  139. #undef FUNC_NAME
  140. SCM_DEFINE (scm_assoc, "assoc", 2, 0, 0,
  141. (SCM key, SCM alist),
  142. "Behaves like @code{assq} but uses @code{equal?} for key comparison.")
  143. #define FUNC_NAME s_scm_assoc
  144. {
  145. SCM ls = alist;
  146. /* Immediate values can be checked using `eq?'. */
  147. if (SCM_IMP (key))
  148. return scm_assq (key, alist);
  149. for(; scm_is_pair (ls); ls = SCM_CDR (ls))
  150. {
  151. SCM tmp = SCM_CAR (ls);
  152. SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
  153. "association list");
  154. if (scm_is_true (scm_equal_p (SCM_CAR (tmp), key)))
  155. return tmp;
  156. }
  157. SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
  158. "association list");
  159. return SCM_BOOL_F;
  160. }
  161. #undef FUNC_NAME
  162. /* Dirk:API2.0:: We should not return #f if the key was not found. In the
  163. * current solution we can not distinguish between finding a (key . #f) pair
  164. * and not finding the key at all.
  165. *
  166. * Possible alternative solutions:
  167. * 1) Remove assq-ref from the API: assq is sufficient.
  168. * 2) Signal an error (what error type?) if the key is not found.
  169. * 3) provide an additional 'default' parameter.
  170. * 3.1) The default parameter is mandatory.
  171. * 3.2) The default parameter is optional, but if no default is given and
  172. * the key is not found, signal an error (what error type?).
  173. */
  174. SCM_DEFINE (scm_assq_ref, "assq-ref", 2, 0, 0,
  175. (SCM alist, SCM key),
  176. "@deffnx {Scheme Procedure} assv-ref alist key\n"
  177. "@deffnx {Scheme Procedure} assoc-ref alist key\n"
  178. "Like @code{assq}, @code{assv} and @code{assoc}, except that only the\n"
  179. "value associated with @var{key} in @var{alist} is returned. These\n"
  180. "functions are equivalent to\n\n"
  181. "@lisp\n"
  182. "(let ((ent (@var{associator} @var{key} @var{alist})))\n"
  183. " (and ent (cdr ent)))\n"
  184. "@end lisp\n\n"
  185. "where @var{associator} is one of @code{assq}, @code{assv} or @code{assoc}.")
  186. #define FUNC_NAME s_scm_assq_ref
  187. {
  188. SCM handle;
  189. handle = scm_sloppy_assq (key, alist);
  190. if (scm_is_pair (handle))
  191. {
  192. return SCM_CDR (handle);
  193. }
  194. return SCM_BOOL_F;
  195. }
  196. #undef FUNC_NAME
  197. SCM_DEFINE (scm_assv_ref, "assv-ref", 2, 0, 0,
  198. (SCM alist, SCM key),
  199. "Behaves like @code{assq-ref} but uses @code{eqv?} for key comparison.")
  200. #define FUNC_NAME s_scm_assv_ref
  201. {
  202. SCM handle;
  203. handle = scm_sloppy_assv (key, alist);
  204. if (scm_is_pair (handle))
  205. {
  206. return SCM_CDR (handle);
  207. }
  208. return SCM_BOOL_F;
  209. }
  210. #undef FUNC_NAME
  211. SCM_DEFINE (scm_assoc_ref, "assoc-ref", 2, 0, 0,
  212. (SCM alist, SCM key),
  213. "Behaves like @code{assq-ref} but uses @code{equal?} for key comparison.")
  214. #define FUNC_NAME s_scm_assoc_ref
  215. {
  216. SCM handle;
  217. handle = scm_sloppy_assoc (key, alist);
  218. if (scm_is_pair (handle))
  219. {
  220. return SCM_CDR (handle);
  221. }
  222. return SCM_BOOL_F;
  223. }
  224. #undef FUNC_NAME
  225. SCM_DEFINE (scm_assq_set_x, "assq-set!", 3, 0, 0,
  226. (SCM alist, SCM key, SCM val),
  227. "@deffnx {Scheme Procedure} assv-set! alist key value\n"
  228. "@deffnx {Scheme Procedure} assoc-set! alist key value\n"
  229. "Reassociate @var{key} in @var{alist} with @var{val}: find any existing\n"
  230. "@var{alist} entry for @var{key} and associate it with the new\n"
  231. "@var{val}. If @var{alist} does not contain an entry for @var{key},\n"
  232. "add a new one. Return the (possibly new) alist.\n\n"
  233. "These functions do not attempt to verify the structure of @var{alist},\n"
  234. "and so may cause unusual results if passed an object that is not an\n"
  235. "association list.")
  236. #define FUNC_NAME s_scm_assq_set_x
  237. {
  238. SCM handle;
  239. handle = scm_sloppy_assq (key, alist);
  240. if (scm_is_pair (handle))
  241. {
  242. scm_set_cdr_x (handle, val);
  243. return alist;
  244. }
  245. else
  246. return scm_acons (key, val, alist);
  247. }
  248. #undef FUNC_NAME
  249. SCM_DEFINE (scm_assv_set_x, "assv-set!", 3, 0, 0,
  250. (SCM alist, SCM key, SCM val),
  251. "Behaves like @code{assq-set!} but uses @code{eqv?} for key comparison.")
  252. #define FUNC_NAME s_scm_assv_set_x
  253. {
  254. SCM handle;
  255. handle = scm_sloppy_assv (key, alist);
  256. if (scm_is_pair (handle))
  257. {
  258. scm_set_cdr_x (handle, val);
  259. return alist;
  260. }
  261. else
  262. return scm_acons (key, val, alist);
  263. }
  264. #undef FUNC_NAME
  265. SCM_DEFINE (scm_assoc_set_x, "assoc-set!", 3, 0, 0,
  266. (SCM alist, SCM key, SCM val),
  267. "Behaves like @code{assq-set!} but uses @code{equal?} for key comparison.")
  268. #define FUNC_NAME s_scm_assoc_set_x
  269. {
  270. SCM handle;
  271. handle = scm_sloppy_assoc (key, alist);
  272. if (scm_is_pair (handle))
  273. {
  274. scm_set_cdr_x (handle, val);
  275. return alist;
  276. }
  277. else
  278. return scm_acons (key, val, alist);
  279. }
  280. #undef FUNC_NAME
  281. SCM_DEFINE (scm_assq_remove_x, "assq-remove!", 2, 0, 0,
  282. (SCM alist, SCM key),
  283. "@deffnx {Scheme Procedure} assv-remove! alist key\n"
  284. "@deffnx {Scheme Procedure} assoc-remove! alist key\n"
  285. "Delete the first entry in @var{alist} associated with @var{key}, and return\n"
  286. "the resulting alist.")
  287. #define FUNC_NAME s_scm_assq_remove_x
  288. {
  289. SCM handle;
  290. handle = scm_sloppy_assq (key, alist);
  291. if (scm_is_pair (handle))
  292. alist = scm_delq1_x (handle, alist);
  293. return alist;
  294. }
  295. #undef FUNC_NAME
  296. SCM_DEFINE (scm_assv_remove_x, "assv-remove!", 2, 0, 0,
  297. (SCM alist, SCM key),
  298. "Behaves like @code{assq-remove!} but uses @code{eqv?} for key comparison.")
  299. #define FUNC_NAME s_scm_assv_remove_x
  300. {
  301. SCM handle;
  302. handle = scm_sloppy_assv (key, alist);
  303. if (scm_is_pair (handle))
  304. alist = scm_delq1_x (handle, alist);
  305. return alist;
  306. }
  307. #undef FUNC_NAME
  308. SCM_DEFINE (scm_assoc_remove_x, "assoc-remove!", 2, 0, 0,
  309. (SCM alist, SCM key),
  310. "Behaves like @code{assq-remove!} but uses @code{equal?} for key comparison.")
  311. #define FUNC_NAME s_scm_assoc_remove_x
  312. {
  313. SCM handle;
  314. handle = scm_sloppy_assoc (key, alist);
  315. if (scm_is_pair (handle))
  316. alist = scm_delq1_x (handle, alist);
  317. return alist;
  318. }
  319. #undef FUNC_NAME
  320. void
  321. scm_init_alist ()
  322. {
  323. #include "alist.x"
  324. }