gsubr.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2008, 2009 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include <alloca.h>
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. #include "libguile/_scm.h"
  25. #include "libguile/procprop.h"
  26. #include "libguile/root.h"
  27. #include "libguile/gsubr.h"
  28. #include "libguile/deprecation.h"
  29. #include "libguile/private-options.h"
  30. /*
  31. * gsubr.c
  32. * Provide `gsubrs' -- subrs taking a prescribed number of required, optional,
  33. * and rest arguments.
  34. */
  35. /* #define GSUBR_TEST */
  36. SCM_GLOBAL_SYMBOL (scm_sym_name, "name");
  37. static SCM
  38. create_gsubr (int define, const char *name,
  39. unsigned int req, unsigned int opt, unsigned int rst,
  40. SCM (*fcn) ())
  41. {
  42. SCM subr;
  43. switch (SCM_GSUBR_MAKTYPE (req, opt, rst))
  44. {
  45. case SCM_GSUBR_MAKTYPE(0, 0, 0):
  46. subr = scm_c_make_subr (name, scm_tc7_subr_0, fcn);
  47. break;
  48. case SCM_GSUBR_MAKTYPE(1, 0, 0):
  49. subr = scm_c_make_subr (name, scm_tc7_subr_1, fcn);
  50. break;
  51. case SCM_GSUBR_MAKTYPE(0, 1, 0):
  52. subr = scm_c_make_subr (name, scm_tc7_subr_1o, fcn);
  53. break;
  54. case SCM_GSUBR_MAKTYPE(1, 1, 0):
  55. subr = scm_c_make_subr (name, scm_tc7_subr_2o, fcn);
  56. break;
  57. case SCM_GSUBR_MAKTYPE(2, 0, 0):
  58. subr = scm_c_make_subr (name, scm_tc7_subr_2, fcn);
  59. break;
  60. case SCM_GSUBR_MAKTYPE(3, 0, 0):
  61. subr = scm_c_make_subr (name, scm_tc7_subr_3, fcn);
  62. break;
  63. case SCM_GSUBR_MAKTYPE(0, 0, 1):
  64. subr = scm_c_make_subr (name, scm_tc7_lsubr, fcn);
  65. break;
  66. case SCM_GSUBR_MAKTYPE(2, 0, 1):
  67. subr = scm_c_make_subr (name, scm_tc7_lsubr_2, fcn);
  68. break;
  69. default:
  70. {
  71. unsigned type;
  72. type = SCM_GSUBR_MAKTYPE (req, opt, rst);
  73. if (SCM_GSUBR_REQ (type) != req
  74. || SCM_GSUBR_OPT (type) != opt
  75. || SCM_GSUBR_REST (type) != rst)
  76. scm_out_of_range ("create_gsubr", scm_from_uint (req + opt + rst));
  77. subr = scm_c_make_subr (name, scm_tc7_gsubr | (type << 8U),
  78. fcn);
  79. }
  80. }
  81. if (define)
  82. scm_define (SCM_SUBR_NAME (subr), subr);
  83. return subr;
  84. }
  85. SCM
  86. scm_c_make_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  87. {
  88. return create_gsubr (0, name, req, opt, rst, fcn);
  89. }
  90. SCM
  91. scm_c_define_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  92. {
  93. return create_gsubr (1, name, req, opt, rst, fcn);
  94. }
  95. static SCM
  96. create_gsubr_with_generic (int define,
  97. const char *name,
  98. int req,
  99. int opt,
  100. int rst,
  101. SCM (*fcn)(),
  102. SCM *gf)
  103. {
  104. SCM subr;
  105. switch (SCM_GSUBR_MAKTYPE(req, opt, rst))
  106. {
  107. case SCM_GSUBR_MAKTYPE(0, 0, 0):
  108. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_0, fcn, gf);
  109. goto create_subr;
  110. case SCM_GSUBR_MAKTYPE(1, 0, 0):
  111. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_1, fcn, gf);
  112. goto create_subr;
  113. case SCM_GSUBR_MAKTYPE(0, 1, 0):
  114. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_1o, fcn, gf);
  115. goto create_subr;
  116. case SCM_GSUBR_MAKTYPE(1, 1, 0):
  117. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_2o, fcn, gf);
  118. goto create_subr;
  119. case SCM_GSUBR_MAKTYPE(2, 0, 0):
  120. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_2, fcn, gf);
  121. goto create_subr;
  122. case SCM_GSUBR_MAKTYPE(3, 0, 0):
  123. subr = scm_c_make_subr_with_generic (name, scm_tc7_subr_3, fcn, gf);
  124. goto create_subr;
  125. case SCM_GSUBR_MAKTYPE(0, 0, 1):
  126. subr = scm_c_make_subr_with_generic (name, scm_tc7_lsubr, fcn, gf);
  127. goto create_subr;
  128. case SCM_GSUBR_MAKTYPE(2, 0, 1):
  129. subr = scm_c_make_subr_with_generic (name, scm_tc7_lsubr_2, fcn, gf);
  130. create_subr:
  131. if (define)
  132. scm_define (SCM_SUBR_NAME (subr), subr);
  133. return subr;
  134. default:
  135. ;
  136. }
  137. scm_misc_error ("scm_c_make_gsubr_with_generic",
  138. "can't make primitive-generic with this arity",
  139. SCM_EOL);
  140. return SCM_BOOL_F; /* never reached */
  141. }
  142. SCM
  143. scm_c_make_gsubr_with_generic (const char *name,
  144. int req,
  145. int opt,
  146. int rst,
  147. SCM (*fcn)(),
  148. SCM *gf)
  149. {
  150. return create_gsubr_with_generic (0, name, req, opt, rst, fcn, gf);
  151. }
  152. SCM
  153. scm_c_define_gsubr_with_generic (const char *name,
  154. int req,
  155. int opt,
  156. int rst,
  157. SCM (*fcn)(),
  158. SCM *gf)
  159. {
  160. return create_gsubr_with_generic (1, name, req, opt, rst, fcn, gf);
  161. }
  162. /* Apply PROC, a gsubr, to the ARGC arguments in ARGV. ARGC is expected to
  163. match the number of arguments of the underlying C function. */
  164. static SCM
  165. gsubr_apply_raw (SCM proc, unsigned int argc, const SCM *argv)
  166. {
  167. SCM (*fcn) ();
  168. unsigned int type, argc_max;
  169. type = SCM_GSUBR_TYPE (proc);
  170. argc_max = SCM_GSUBR_REQ (type) + SCM_GSUBR_OPT (type)
  171. + SCM_GSUBR_REST (type);
  172. if (SCM_UNLIKELY (argc != argc_max))
  173. /* We expect the exact argument count. */
  174. scm_wrong_num_args (SCM_SUBR_NAME (proc));
  175. fcn = SCM_SUBRF (proc);
  176. switch (argc)
  177. {
  178. case 0:
  179. return (*fcn) ();
  180. case 1:
  181. return (*fcn) (argv[0]);
  182. case 2:
  183. return (*fcn) (argv[0], argv[1]);
  184. case 3:
  185. return (*fcn) (argv[0], argv[1], argv[2]);
  186. case 4:
  187. return (*fcn) (argv[0], argv[1], argv[2], argv[3]);
  188. case 5:
  189. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4]);
  190. case 6:
  191. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
  192. case 7:
  193. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
  194. argv[6]);
  195. case 8:
  196. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
  197. argv[6], argv[7]);
  198. case 9:
  199. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
  200. argv[6], argv[7], argv[8]);
  201. case 10:
  202. return (*fcn) (argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
  203. argv[6], argv[7], argv[8], argv[9]);
  204. default:
  205. scm_misc_error ((char *) SCM_SUBR_NAME (proc),
  206. "gsubr invocation with more than 10 arguments not implemented",
  207. SCM_EOL);
  208. }
  209. return SCM_BOOL_F; /* Never reached. */
  210. }
  211. /* Apply PROC, a gsubr, to the given arguments. Missing optional arguments
  212. are added, and rest arguments are turned into a list. */
  213. SCM
  214. scm_i_gsubr_apply (SCM proc, SCM arg, ...)
  215. {
  216. unsigned int type, argc, argc_max;
  217. SCM *argv;
  218. va_list arg_list;
  219. type = SCM_GSUBR_TYPE (proc);
  220. argc_max = SCM_GSUBR_REQ (type) + SCM_GSUBR_OPT (type);
  221. argv = alloca ((argc_max + SCM_GSUBR_REST (type)) * sizeof (*argv));
  222. va_start (arg_list, arg);
  223. for (argc = 0;
  224. !SCM_UNBNDP (arg) && argc < argc_max;
  225. argc++, arg = va_arg (arg_list, SCM))
  226. argv[argc] = arg;
  227. if (SCM_UNLIKELY (argc < SCM_GSUBR_REQ (type)))
  228. scm_wrong_num_args (SCM_SUBR_NAME (proc));
  229. /* Fill in optional arguments that were not passed. */
  230. while (argc < argc_max)
  231. argv[argc++] = SCM_UNDEFINED;
  232. if (SCM_GSUBR_REST (type))
  233. {
  234. /* Accumulate rest arguments in a list. */
  235. SCM *rest_loc;
  236. argv[argc_max] = SCM_EOL;
  237. for (rest_loc = &argv[argc_max];
  238. !SCM_UNBNDP (arg);
  239. rest_loc = SCM_CDRLOC (*rest_loc), arg = va_arg (arg_list, SCM))
  240. *rest_loc = scm_cons (arg, SCM_EOL);
  241. argc = argc_max + 1;
  242. }
  243. va_end (arg_list);
  244. return gsubr_apply_raw (proc, argc, argv);
  245. }
  246. /* Apply SELF, a gsubr, to the arguments listed in ARGS. Missing optional
  247. arguments are added, and rest arguments are kept into a list. */
  248. SCM
  249. scm_i_gsubr_apply_list (SCM self, SCM args)
  250. #define FUNC_NAME "scm_i_gsubr_apply"
  251. {
  252. SCM v[SCM_GSUBR_MAX];
  253. unsigned int typ = SCM_GSUBR_TYPE (self);
  254. long i, n = SCM_GSUBR_REQ (typ) + SCM_GSUBR_OPT (typ) + SCM_GSUBR_REST (typ);
  255. for (i = 0; i < SCM_GSUBR_REQ (typ); i++) {
  256. if (scm_is_null (args))
  257. scm_wrong_num_args (SCM_SUBR_NAME (self));
  258. v[i] = SCM_CAR(args);
  259. args = SCM_CDR(args);
  260. }
  261. for (; i < SCM_GSUBR_REQ (typ) + SCM_GSUBR_OPT (typ); i++) {
  262. if (SCM_NIMP (args)) {
  263. v[i] = SCM_CAR (args);
  264. args = SCM_CDR(args);
  265. }
  266. else
  267. v[i] = SCM_UNDEFINED;
  268. }
  269. if (SCM_GSUBR_REST(typ))
  270. v[i] = args;
  271. else if (!scm_is_null (args))
  272. scm_wrong_num_args (SCM_SUBR_NAME (self));
  273. return gsubr_apply_raw (self, n, v);
  274. }
  275. #undef FUNC_NAME
  276. #ifdef GSUBR_TEST
  277. /* A silly example, taking 2 required args, 1 optional, and
  278. a scm_list of rest args
  279. */
  280. SCM
  281. gsubr_21l(SCM req1, SCM req2, SCM opt, SCM rst)
  282. {
  283. scm_puts ("gsubr-2-1-l:\n req1: ", scm_cur_outp);
  284. scm_display(req1, scm_cur_outp);
  285. scm_puts ("\n req2: ", scm_cur_outp);
  286. scm_display(req2, scm_cur_outp);
  287. scm_puts ("\n opt: ", scm_cur_outp);
  288. scm_display(opt, scm_cur_outp);
  289. scm_puts ("\n rest: ", scm_cur_outp);
  290. scm_display(rst, scm_cur_outp);
  291. scm_newline(scm_cur_outp);
  292. return SCM_UNSPECIFIED;
  293. }
  294. #endif
  295. void
  296. scm_init_gsubr()
  297. {
  298. #ifdef GSUBR_TEST
  299. scm_c_define_gsubr ("gsubr-2-1-l", 2, 1, 1, gsubr_21l); /* example */
  300. #endif
  301. #include "libguile/gsubr.x"
  302. }
  303. /*
  304. Local Variables:
  305. c-file-style: "gnu"
  306. End:
  307. */