memoize.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
  2. * 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
  3. * Free Software Foundation, Inc.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public License
  7. * as published by the Free Software Foundation; either version 3 of
  8. * the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18. * 02110-1301 USA
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23. #include "libguile/__scm.h"
  24. #include "libguile/_scm.h"
  25. #include "libguile/continuations.h"
  26. #include "libguile/eq.h"
  27. #include "libguile/expand.h"
  28. #include "libguile/list.h"
  29. #include "libguile/macros.h"
  30. #include "libguile/memoize.h"
  31. #include "libguile/modules.h"
  32. #include "libguile/srcprop.h"
  33. #include "libguile/ports.h"
  34. #include "libguile/print.h"
  35. #include "libguile/strings.h"
  36. #include "libguile/throw.h"
  37. #include "libguile/validate.h"
  38. #define CAR(x) SCM_CAR(x)
  39. #define CDR(x) SCM_CDR(x)
  40. #define CAAR(x) SCM_CAAR(x)
  41. #define CADR(x) SCM_CADR(x)
  42. #define CDAR(x) SCM_CDAR(x)
  43. #define CDDR(x) SCM_CDDR(x)
  44. #define CADDR(x) SCM_CADDR(x)
  45. #define CDDDR(x) SCM_CDDDR(x)
  46. #define CADDDR(x) SCM_CADDDR(x)
  47. #define VECTOR_REF(v, i) (SCM_SIMPLE_VECTOR_REF (v, i))
  48. #define VECTOR_SET(v, i, x) (SCM_SIMPLE_VECTOR_SET (v, i, x))
  49. #define VECTOR_LENGTH(v) (SCM_SIMPLE_VECTOR_LENGTH (v))
  50. SCM_SYMBOL (sym_case_lambda_star, "case-lambda*");
  51. /* Primitives not exposed to general Scheme. */
  52. static SCM wind;
  53. static SCM unwind;
  54. static SCM push_fluid;
  55. static SCM pop_fluid;
  56. static SCM
  57. do_wind (SCM in, SCM out)
  58. {
  59. scm_dynstack_push_dynwind (&SCM_I_CURRENT_THREAD->dynstack, in, out);
  60. return SCM_UNSPECIFIED;
  61. }
  62. static SCM
  63. do_unwind (void)
  64. {
  65. scm_dynstack_pop (&SCM_I_CURRENT_THREAD->dynstack);
  66. return SCM_UNSPECIFIED;
  67. }
  68. static SCM
  69. do_push_fluid (SCM fluid, SCM val)
  70. {
  71. scm_i_thread *thread = SCM_I_CURRENT_THREAD;
  72. scm_dynstack_push_fluid (&thread->dynstack, fluid, val,
  73. thread->dynamic_state);
  74. return SCM_UNSPECIFIED;
  75. }
  76. static SCM
  77. do_pop_fluid (void)
  78. {
  79. scm_i_thread *thread = SCM_I_CURRENT_THREAD;
  80. scm_dynstack_unwind_fluid (&thread->dynstack, thread->dynamic_state);
  81. return SCM_UNSPECIFIED;
  82. }
  83. /* {Evaluator memoized expressions}
  84. */
  85. scm_t_bits scm_tc16_memoized;
  86. #define MAKMEMO(n, args) \
  87. (scm_cons (SCM_I_MAKINUM (n), args))
  88. #define MAKMEMO_SEQ(head,tail) \
  89. MAKMEMO (SCM_M_SEQ, scm_cons (head, tail))
  90. #define MAKMEMO_IF(test, then, else_) \
  91. MAKMEMO (SCM_M_IF, scm_cons (test, scm_cons (then, else_)))
  92. #define FIXED_ARITY(nreq) \
  93. scm_list_1 (SCM_I_MAKINUM (nreq))
  94. #define REST_ARITY(nreq, rest) \
  95. scm_list_2 (SCM_I_MAKINUM (nreq), rest)
  96. #define FULL_ARITY(nreq, rest, nopt, kw, inits, alt) \
  97. scm_list_n (SCM_I_MAKINUM (nreq), rest, SCM_I_MAKINUM (nopt), kw, inits, \
  98. alt, SCM_UNDEFINED)
  99. #define MAKMEMO_LAMBDA(body, arity, meta) \
  100. MAKMEMO (SCM_M_LAMBDA, \
  101. scm_cons (body, scm_cons (meta, arity)))
  102. #define MAKMEMO_LET(inits, body) \
  103. MAKMEMO (SCM_M_LET, scm_cons (inits, body))
  104. #define MAKMEMO_QUOTE(exp) \
  105. MAKMEMO (SCM_M_QUOTE, exp)
  106. #define MAKMEMO_DEFINE(var, val) \
  107. MAKMEMO (SCM_M_DEFINE, scm_cons (var, val))
  108. #define MAKMEMO_CAPTURE_MODULE(exp) \
  109. MAKMEMO (SCM_M_CAPTURE_MODULE, exp)
  110. #define MAKMEMO_APPLY(proc, args)\
  111. MAKMEMO (SCM_M_APPLY, scm_list_2 (proc, args))
  112. #define MAKMEMO_CONT(proc) \
  113. MAKMEMO (SCM_M_CONT, proc)
  114. #define MAKMEMO_CALL_WITH_VALUES(prod, cons) \
  115. MAKMEMO (SCM_M_CALL_WITH_VALUES, scm_cons (prod, cons))
  116. #define MAKMEMO_CALL(proc, nargs, args) \
  117. MAKMEMO (SCM_M_CALL, scm_cons (proc, scm_cons (SCM_I_MAKINUM (nargs), args)))
  118. #define MAKMEMO_LEX_REF(pos) \
  119. MAKMEMO (SCM_M_LEXICAL_REF, pos)
  120. #define MAKMEMO_LEX_SET(pos, val) \
  121. MAKMEMO (SCM_M_LEXICAL_SET, scm_cons (pos, val))
  122. #define MAKMEMO_TOP_REF(var) \
  123. MAKMEMO (SCM_M_TOPLEVEL_REF, var)
  124. #define MAKMEMO_TOP_SET(var, val) \
  125. MAKMEMO (SCM_M_TOPLEVEL_SET, scm_cons (var, val))
  126. #define MAKMEMO_MOD_REF(mod, var, public) \
  127. MAKMEMO (SCM_M_MODULE_REF, scm_cons (mod, scm_cons (var, public)))
  128. #define MAKMEMO_MOD_SET(val, mod, var, public) \
  129. MAKMEMO (SCM_M_MODULE_SET, scm_cons (val, scm_cons (mod, scm_cons (var, public))))
  130. #define MAKMEMO_CALL_WITH_PROMPT(tag, thunk, handler) \
  131. MAKMEMO (SCM_M_CALL_WITH_PROMPT, scm_cons (tag, scm_cons (thunk, handler)))
  132. /* This table must agree with the list of M_ constants in memoize.h */
  133. static const char *const memoized_tags[] =
  134. {
  135. "seq",
  136. "if",
  137. "lambda",
  138. "let",
  139. "quote",
  140. "define",
  141. "capture-module",
  142. "apply",
  143. "call/cc",
  144. "call-with-values",
  145. "call",
  146. "lexical-ref",
  147. "lexical-set!",
  148. "toplevel-ref",
  149. "toplevel-set!",
  150. "module-ref",
  151. "module-set!",
  152. "call-with-prompt",
  153. };
  154. static int
  155. try_lookup_rib (SCM x, SCM rib)
  156. {
  157. int idx = 0;
  158. for (; idx < VECTOR_LENGTH (rib); idx++)
  159. if (scm_is_eq (x, VECTOR_REF (rib, idx)))
  160. return idx; /* bound */
  161. return -1;
  162. }
  163. static int
  164. lookup_rib (SCM x, SCM rib)
  165. {
  166. int idx = try_lookup_rib (x, rib);
  167. if (idx < 0)
  168. abort ();
  169. return idx;
  170. }
  171. static SCM
  172. make_pos (int depth, int width)
  173. {
  174. return scm_cons (SCM_I_MAKINUM (depth), SCM_I_MAKINUM (width));
  175. }
  176. static SCM
  177. lookup (SCM x, SCM env)
  178. {
  179. int d = 0;
  180. for (; scm_is_pair (env); env = CDR (env), d++)
  181. {
  182. int w = try_lookup_rib (x, CAR (env));
  183. if (w < 0)
  184. continue;
  185. return make_pos (d, w);
  186. }
  187. abort ();
  188. }
  189. /* Abbreviate SCM_EXPANDED_REF. Copied because I'm not sure about symbol pasting */
  190. #define REF(x,type,field) \
  191. (scm_struct_ref (x, SCM_I_MAKINUM (SCM_EXPANDED_##type##_##field)))
  192. static SCM list_of_guile = SCM_BOOL_F;
  193. static SCM memoize (SCM exp, SCM env);
  194. static SCM
  195. memoize_exps (SCM exps, SCM env)
  196. {
  197. SCM ret;
  198. for (ret = SCM_EOL; scm_is_pair (exps); exps = CDR (exps))
  199. ret = scm_cons (memoize (CAR (exps), env), ret);
  200. return scm_reverse_x (ret, SCM_UNDEFINED);
  201. }
  202. static SCM
  203. capture_env (SCM env)
  204. {
  205. if (scm_is_false (env))
  206. return SCM_BOOL_T;
  207. return env;
  208. }
  209. static SCM
  210. maybe_makmemo_capture_module (SCM exp, SCM env)
  211. {
  212. if (scm_is_false (env))
  213. return MAKMEMO_CAPTURE_MODULE (exp);
  214. return exp;
  215. }
  216. static SCM
  217. memoize (SCM exp, SCM env)
  218. {
  219. if (!SCM_EXPANDED_P (exp))
  220. abort ();
  221. switch (SCM_EXPANDED_TYPE (exp))
  222. {
  223. case SCM_EXPANDED_VOID:
  224. return MAKMEMO_QUOTE (SCM_UNSPECIFIED);
  225. case SCM_EXPANDED_CONST:
  226. return MAKMEMO_QUOTE (REF (exp, CONST, EXP));
  227. case SCM_EXPANDED_PRIMITIVE_REF:
  228. if (scm_is_eq (scm_current_module (), scm_the_root_module ()))
  229. return maybe_makmemo_capture_module
  230. (MAKMEMO_TOP_REF (REF (exp, PRIMITIVE_REF, NAME)),
  231. env);
  232. else
  233. return MAKMEMO_MOD_REF (list_of_guile, REF (exp, PRIMITIVE_REF, NAME),
  234. SCM_BOOL_F);
  235. case SCM_EXPANDED_LEXICAL_REF:
  236. return MAKMEMO_LEX_REF (lookup (REF (exp, LEXICAL_REF, GENSYM), env));
  237. case SCM_EXPANDED_LEXICAL_SET:
  238. return MAKMEMO_LEX_SET (lookup (REF (exp, LEXICAL_SET, GENSYM), env),
  239. memoize (REF (exp, LEXICAL_SET, EXP), env));
  240. case SCM_EXPANDED_MODULE_REF:
  241. return MAKMEMO_MOD_REF (REF (exp, MODULE_REF, MOD),
  242. REF (exp, MODULE_REF, NAME),
  243. REF (exp, MODULE_REF, PUBLIC));
  244. case SCM_EXPANDED_MODULE_SET:
  245. return MAKMEMO_MOD_SET (memoize (REF (exp, MODULE_SET, EXP), env),
  246. REF (exp, MODULE_SET, MOD),
  247. REF (exp, MODULE_SET, NAME),
  248. REF (exp, MODULE_SET, PUBLIC));
  249. case SCM_EXPANDED_TOPLEVEL_REF:
  250. return maybe_makmemo_capture_module
  251. (MAKMEMO_TOP_REF (REF (exp, TOPLEVEL_REF, NAME)), env);
  252. case SCM_EXPANDED_TOPLEVEL_SET:
  253. return maybe_makmemo_capture_module
  254. (MAKMEMO_TOP_SET (REF (exp, TOPLEVEL_SET, NAME),
  255. memoize (REF (exp, TOPLEVEL_SET, EXP),
  256. capture_env (env))),
  257. env);
  258. case SCM_EXPANDED_TOPLEVEL_DEFINE:
  259. return MAKMEMO_DEFINE (REF (exp, TOPLEVEL_DEFINE, NAME),
  260. memoize (REF (exp, TOPLEVEL_DEFINE, EXP), env));
  261. case SCM_EXPANDED_CONDITIONAL:
  262. return MAKMEMO_IF (memoize (REF (exp, CONDITIONAL, TEST), env),
  263. memoize (REF (exp, CONDITIONAL, CONSEQUENT), env),
  264. memoize (REF (exp, CONDITIONAL, ALTERNATE), env));
  265. case SCM_EXPANDED_CALL:
  266. {
  267. SCM proc, args;
  268. proc = REF (exp, CALL, PROC);
  269. args = memoize_exps (REF (exp, CALL, ARGS), env);
  270. return MAKMEMO_CALL (memoize (proc, env), scm_ilength (args), args);
  271. }
  272. case SCM_EXPANDED_PRIMCALL:
  273. {
  274. SCM name, args;
  275. int nargs;
  276. name = REF (exp, PRIMCALL, NAME);
  277. args = memoize_exps (REF (exp, PRIMCALL, ARGS), env);
  278. nargs = scm_ilength (args);
  279. if (nargs == 3
  280. && scm_is_eq (name, scm_from_latin1_symbol ("call-with-prompt")))
  281. return MAKMEMO_CALL_WITH_PROMPT (CAR (args),
  282. CADR (args),
  283. CADDR (args));
  284. else if (nargs == 2
  285. && scm_is_eq (name, scm_from_latin1_symbol ("apply")))
  286. return MAKMEMO_APPLY (CAR (args), CADR (args));
  287. else if (nargs == 1
  288. && scm_is_eq (name,
  289. scm_from_latin1_symbol
  290. ("call-with-current-continuation")))
  291. return MAKMEMO_CONT (CAR (args));
  292. else if (nargs == 2
  293. && scm_is_eq (name,
  294. scm_from_latin1_symbol ("call-with-values")))
  295. return MAKMEMO_CALL_WITH_VALUES (CAR (args), CADR (args));
  296. else if (nargs == 2
  297. && scm_is_eq (name, scm_from_latin1_symbol ("wind")))
  298. return MAKMEMO_CALL (MAKMEMO_QUOTE (wind), 2, args);
  299. else if (nargs == 0
  300. && scm_is_eq (name, scm_from_latin1_symbol ("unwind")))
  301. return MAKMEMO_CALL (MAKMEMO_QUOTE (unwind), 0, SCM_EOL);
  302. else if (nargs == 2
  303. && scm_is_eq (name, scm_from_latin1_symbol ("push-fluid")))
  304. return MAKMEMO_CALL (MAKMEMO_QUOTE (push_fluid), 2, args);
  305. else if (nargs == 0
  306. && scm_is_eq (name, scm_from_latin1_symbol ("pop-fluid")))
  307. return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_fluid), 0, SCM_EOL);
  308. else if (scm_is_eq (scm_current_module (), scm_the_root_module ()))
  309. return MAKMEMO_CALL (maybe_makmemo_capture_module
  310. (MAKMEMO_TOP_REF (name), env),
  311. nargs, args);
  312. else
  313. return MAKMEMO_CALL (MAKMEMO_MOD_REF (list_of_guile, name,
  314. SCM_BOOL_F),
  315. nargs,
  316. args);
  317. }
  318. case SCM_EXPANDED_SEQ:
  319. return MAKMEMO_SEQ (memoize (REF (exp, SEQ, HEAD), env),
  320. memoize (REF (exp, SEQ, TAIL), env));
  321. case SCM_EXPANDED_LAMBDA:
  322. /* The body will be a lambda-case or #f. */
  323. {
  324. SCM meta, body, proc;
  325. meta = REF (exp, LAMBDA, META);
  326. body = REF (exp, LAMBDA, BODY);
  327. if (scm_is_false (body))
  328. /* Give a body to case-lambda with no clauses. */
  329. proc = MAKMEMO_LAMBDA
  330. (MAKMEMO_CALL
  331. (MAKMEMO_MOD_REF (list_of_guile,
  332. scm_from_latin1_symbol ("throw"),
  333. SCM_BOOL_F),
  334. 5,
  335. scm_list_5 (MAKMEMO_QUOTE (scm_args_number_key),
  336. MAKMEMO_QUOTE (SCM_BOOL_F),
  337. MAKMEMO_QUOTE (scm_from_latin1_string
  338. ("Wrong number of arguments")),
  339. MAKMEMO_QUOTE (SCM_EOL),
  340. MAKMEMO_QUOTE (SCM_BOOL_F))),
  341. FIXED_ARITY (0),
  342. meta);
  343. else
  344. {
  345. proc = memoize (body, capture_env (env));
  346. SCM_SETCAR (SCM_CDR (SCM_MEMOIZED_ARGS (proc)), meta);
  347. }
  348. return maybe_makmemo_capture_module (proc, env);
  349. }
  350. case SCM_EXPANDED_LAMBDA_CASE:
  351. {
  352. SCM req, rest, opt, kw, inits, vars, body, alt;
  353. SCM walk, minits, arity, rib, new_env;
  354. int nreq, nopt;
  355. req = REF (exp, LAMBDA_CASE, REQ);
  356. rest = scm_not (scm_not (REF (exp, LAMBDA_CASE, REST)));
  357. opt = REF (exp, LAMBDA_CASE, OPT);
  358. kw = REF (exp, LAMBDA_CASE, KW);
  359. inits = REF (exp, LAMBDA_CASE, INITS);
  360. vars = REF (exp, LAMBDA_CASE, GENSYMS);
  361. body = REF (exp, LAMBDA_CASE, BODY);
  362. alt = REF (exp, LAMBDA_CASE, ALTERNATE);
  363. nreq = scm_ilength (req);
  364. nopt = scm_is_pair (opt) ? scm_ilength (opt) : 0;
  365. /* The vars are the gensyms, according to the divine plan. But we need
  366. to memoize the inits within their appropriate environment,
  367. complicating things. */
  368. rib = scm_vector (vars);
  369. new_env = scm_cons (rib, env);
  370. minits = SCM_EOL;
  371. for (walk = inits; scm_is_pair (walk); walk = CDR (walk))
  372. minits = scm_cons (memoize (CAR (walk), new_env), minits);
  373. minits = scm_reverse_x (minits, SCM_UNDEFINED);
  374. if (scm_is_true (kw))
  375. {
  376. /* (aok? (kw name sym) ...) -> (aok? (kw . index) ...) */
  377. SCM aok = CAR (kw), indices = SCM_EOL;
  378. for (kw = CDR (kw); scm_is_pair (kw); kw = CDR (kw))
  379. {
  380. SCM k;
  381. int idx;
  382. k = CAR (CAR (kw));
  383. idx = lookup_rib (CADDR (CAR (kw)), rib);
  384. indices = scm_acons (k, SCM_I_MAKINUM (idx), indices);
  385. }
  386. kw = scm_cons (aok, scm_reverse_x (indices, SCM_UNDEFINED));
  387. }
  388. if (scm_is_false (alt) && scm_is_false (kw) && scm_is_false (opt))
  389. {
  390. if (scm_is_false (rest))
  391. arity = FIXED_ARITY (nreq);
  392. else
  393. arity = REST_ARITY (nreq, SCM_BOOL_T);
  394. }
  395. else if (scm_is_true (alt))
  396. arity = FULL_ARITY (nreq, rest, nopt, kw, minits,
  397. SCM_MEMOIZED_ARGS (memoize (alt, env)));
  398. else
  399. arity = FULL_ARITY (nreq, rest, nopt, kw, minits, SCM_BOOL_F);
  400. return MAKMEMO_LAMBDA (memoize (body, new_env), arity,
  401. SCM_BOOL_F /* meta, filled in later */);
  402. }
  403. case SCM_EXPANDED_LET:
  404. {
  405. SCM vars, exps, body, varsv, inits, new_env;
  406. int i;
  407. vars = REF (exp, LET, GENSYMS);
  408. exps = REF (exp, LET, VALS);
  409. body = REF (exp, LET, BODY);
  410. varsv = scm_vector (vars);
  411. inits = scm_c_make_vector (VECTOR_LENGTH (varsv),
  412. SCM_BOOL_F);
  413. new_env = scm_cons (varsv, capture_env (env));
  414. for (i = 0; scm_is_pair (exps); exps = CDR (exps), i++)
  415. VECTOR_SET (inits, i, memoize (CAR (exps), env));
  416. return maybe_makmemo_capture_module
  417. (MAKMEMO_LET (inits, memoize (body, new_env)), env);
  418. }
  419. case SCM_EXPANDED_LETREC:
  420. {
  421. SCM vars, varsv, exps, expsv, body, undefs, new_env;
  422. int i, nvars, in_order_p;
  423. vars = REF (exp, LETREC, GENSYMS);
  424. exps = REF (exp, LETREC, VALS);
  425. body = REF (exp, LETREC, BODY);
  426. in_order_p = scm_is_true (REF (exp, LETREC, IN_ORDER_P));
  427. varsv = scm_vector (vars);
  428. nvars = VECTOR_LENGTH (varsv);
  429. expsv = scm_vector (exps);
  430. undefs = scm_c_make_vector (nvars, MAKMEMO_QUOTE (SCM_UNDEFINED));
  431. new_env = scm_cons (varsv, capture_env (env));
  432. if (in_order_p)
  433. {
  434. SCM body_exps = memoize (body, new_env);
  435. for (i = nvars - 1; i >= 0; i--)
  436. {
  437. SCM init = memoize (VECTOR_REF (expsv, i), new_env);
  438. body_exps = MAKMEMO_SEQ (MAKMEMO_LEX_SET (make_pos (0, i), init),
  439. body_exps);
  440. }
  441. return maybe_makmemo_capture_module
  442. (MAKMEMO_LET (undefs, body_exps), env);
  443. }
  444. else
  445. {
  446. SCM sets = SCM_BOOL_F, inits = scm_c_make_vector (nvars, SCM_BOOL_F);
  447. for (i = nvars - 1; i >= 0; i--)
  448. {
  449. SCM init, set;
  450. init = memoize (VECTOR_REF (expsv, i), new_env);
  451. VECTOR_SET (inits, i, init);
  452. set = MAKMEMO_LEX_SET (make_pos (1, i),
  453. MAKMEMO_LEX_REF (make_pos (0, i)));
  454. if (scm_is_false (sets))
  455. sets = set;
  456. else
  457. sets = MAKMEMO_SEQ (set, sets);
  458. }
  459. if (scm_is_false (sets))
  460. return memoize (body, env);
  461. return maybe_makmemo_capture_module
  462. (MAKMEMO_LET (undefs,
  463. MAKMEMO_SEQ (MAKMEMO_LET (inits, sets),
  464. memoize (body, new_env))),
  465. env);
  466. }
  467. }
  468. default:
  469. abort ();
  470. }
  471. }
  472. SCM_DEFINE (scm_memoize_expression, "memoize-expression", 1, 0, 0,
  473. (SCM exp),
  474. "Memoize the expression @var{exp}.")
  475. #define FUNC_NAME s_scm_memoize_expression
  476. {
  477. SCM_ASSERT_TYPE (SCM_EXPANDED_P (exp), exp, 1, FUNC_NAME, "expanded");
  478. return memoize (exp, SCM_BOOL_F);
  479. }
  480. #undef FUNC_NAME
  481. SCM_SYMBOL (sym_placeholder, "_");
  482. static SCM unmemoize (SCM expr);
  483. static SCM
  484. unmemoize_exprs (SCM exprs)
  485. {
  486. SCM ret, tail;
  487. if (scm_is_null (exprs))
  488. return SCM_EOL;
  489. ret = scm_list_1 (unmemoize (CAR (exprs)));
  490. tail = ret;
  491. for (exprs = CDR (exprs); !scm_is_null (exprs); exprs = CDR (exprs))
  492. {
  493. SCM_SETCDR (tail, scm_list_1 (unmemoize (CAR (exprs))));
  494. tail = CDR (tail);
  495. }
  496. return ret;
  497. }
  498. static SCM
  499. unmemoize_bindings (SCM inits)
  500. {
  501. SCM ret = SCM_EOL;
  502. int n = scm_c_vector_length (inits);
  503. while (n--)
  504. ret = scm_cons (unmemoize (scm_c_vector_ref (inits, n)), ret);
  505. return ret;
  506. }
  507. static SCM
  508. unmemoize_lexical (SCM n)
  509. {
  510. char buf[32];
  511. buf[31] = 0;
  512. snprintf (buf, 31, "<%u,%u>", scm_to_uint32 (CAR (n)),
  513. scm_to_uint32 (CDR (n)));
  514. return scm_from_utf8_symbol (buf);
  515. }
  516. static SCM
  517. unmemoize (const SCM expr)
  518. {
  519. SCM args;
  520. args = SCM_MEMOIZED_ARGS (expr);
  521. switch (SCM_MEMOIZED_TAG (expr))
  522. {
  523. case SCM_M_APPLY:
  524. return scm_cons (scm_from_latin1_symbol ("apply"),
  525. unmemoize_exprs (args));
  526. case SCM_M_SEQ:
  527. return scm_list_3 (scm_sym_begin, unmemoize (CAR (args)),
  528. unmemoize (CDR (args)));
  529. case SCM_M_CALL:
  530. return scm_cons (unmemoize (CAR (args)), unmemoize_exprs (CDDR (args)));
  531. case SCM_M_CONT:
  532. return scm_list_2 (scm_from_latin1_symbol
  533. ("call-with-current_continuation"),
  534. unmemoize (args));
  535. case SCM_M_CALL_WITH_VALUES:
  536. return scm_list_3 (scm_from_latin1_symbol ("call-with-values"),
  537. unmemoize (CAR (args)), unmemoize (CDR (args)));
  538. case SCM_M_DEFINE:
  539. return scm_list_3 (scm_sym_define, CAR (args), unmemoize (CDR (args)));
  540. case SCM_M_CAPTURE_MODULE:
  541. return scm_list_2 (scm_from_latin1_symbol ("capture-module"),
  542. unmemoize (args));
  543. case SCM_M_IF:
  544. return scm_list_4 (scm_sym_if, unmemoize (scm_car (args)),
  545. unmemoize (scm_cadr (args)), unmemoize (scm_cddr (args)));
  546. case SCM_M_LAMBDA:
  547. {
  548. SCM body = CAR (args), spec = CDDR (args);
  549. if (scm_is_null (CDR (spec)))
  550. return scm_list_3 (scm_sym_lambda,
  551. scm_make_list (CAR (spec), sym_placeholder),
  552. unmemoize (CAR (args)));
  553. else if (scm_is_null (SCM_CDDR (spec)))
  554. {
  555. SCM formals = scm_make_list (CAR (spec), sym_placeholder);
  556. return scm_list_3 (scm_sym_lambda,
  557. scm_is_true (CADR (spec))
  558. ? scm_cons_star (sym_placeholder, formals)
  559. : formals,
  560. unmemoize (CAR (args)));
  561. }
  562. else
  563. {
  564. SCM alt, tail;
  565. alt = CADDR (CDDDR (spec));
  566. if (scm_is_true (alt))
  567. tail = CDR (unmemoize (alt));
  568. else
  569. tail = SCM_EOL;
  570. return scm_cons
  571. (sym_case_lambda_star,
  572. scm_cons (scm_list_2 (scm_list_5 (CAR (spec),
  573. CADR (spec),
  574. CADDR (spec),
  575. CADDDR (spec),
  576. unmemoize_exprs (CADR (CDDDR (spec)))),
  577. unmemoize (body)),
  578. tail));
  579. }
  580. }
  581. case SCM_M_LET:
  582. return scm_list_3 (scm_sym_let,
  583. unmemoize_bindings (CAR (args)),
  584. unmemoize (CDR (args)));
  585. case SCM_M_QUOTE:
  586. return scm_list_2 (scm_sym_quote, args);
  587. case SCM_M_LEXICAL_REF:
  588. return unmemoize_lexical (args);
  589. case SCM_M_LEXICAL_SET:
  590. return scm_list_3 (scm_sym_set_x, unmemoize_lexical (CAR (args)),
  591. unmemoize (CDR (args)));
  592. case SCM_M_TOPLEVEL_REF:
  593. return args;
  594. case SCM_M_TOPLEVEL_SET:
  595. return scm_list_3 (scm_sym_set_x, CAR (args), unmemoize (CDR (args)));
  596. case SCM_M_MODULE_REF:
  597. return SCM_VARIABLEP (args) ? args
  598. : scm_list_3 (scm_is_true (CDDR (args)) ? scm_sym_at : scm_sym_atat,
  599. scm_i_finite_list_copy (CAR (args)),
  600. CADR (args));
  601. case SCM_M_MODULE_SET:
  602. return scm_list_3 (scm_sym_set_x,
  603. SCM_VARIABLEP (CDR (args)) ? CDR (args)
  604. : scm_list_3 (scm_is_true (CDDDR (args))
  605. ? scm_sym_at : scm_sym_atat,
  606. scm_i_finite_list_copy (CADR (args)),
  607. CADDR (args)),
  608. unmemoize (CAR (args)));
  609. case SCM_M_CALL_WITH_PROMPT:
  610. return scm_list_4 (scm_from_latin1_symbol ("call-with-prompt"),
  611. unmemoize (CAR (args)),
  612. unmemoize (CADR (args)),
  613. unmemoize (CDDR (args)));
  614. default:
  615. abort ();
  616. }
  617. }
  618. SCM_DEFINE (scm_unmemoize_expression, "unmemoize-expression", 1, 0, 0,
  619. (SCM m),
  620. "Unmemoize the memoized expression @var{m}.")
  621. #define FUNC_NAME s_scm_unmemoize_expression
  622. {
  623. return unmemoize (m);
  624. }
  625. #undef FUNC_NAME
  626. SCM_DEFINE (scm_memoized_typecode, "memoized-typecode", 1, 0, 0,
  627. (SCM sym),
  628. "Return the memoized typecode corresponding to the symbol @var{sym}.")
  629. #define FUNC_NAME s_scm_memoized_typecode
  630. {
  631. int i;
  632. SCM_VALIDATE_SYMBOL (1, sym);
  633. for (i = 0; i < sizeof(memoized_tags)/sizeof(const char*); i++)
  634. if (strcmp (scm_i_symbol_chars (sym), memoized_tags[i]) == 0)
  635. return scm_from_int32 (i);
  636. return SCM_BOOL_F;
  637. }
  638. #undef FUNC_NAME
  639. SCM_SYMBOL (scm_unbound_variable_key, "unbound-variable");
  640. static void error_unbound_variable (SCM symbol) SCM_NORETURN;
  641. static void error_unbound_variable (SCM symbol)
  642. {
  643. scm_error (scm_unbound_variable_key, NULL, "Unbound variable: ~S",
  644. scm_list_1 (symbol), SCM_BOOL_F);
  645. }
  646. SCM_DEFINE (scm_memoize_variable_access_x, "memoize-variable-access!", 2, 0, 0,
  647. (SCM m, SCM mod),
  648. "Look up and cache the variable that @var{m} will access, returning the variable.")
  649. #define FUNC_NAME s_scm_memoize_variable_access_x
  650. {
  651. SCM mx = SCM_MEMOIZED_ARGS (m);
  652. if (scm_is_false (mod))
  653. mod = scm_the_root_module ();
  654. switch (SCM_MEMOIZED_TAG (m))
  655. {
  656. case SCM_M_TOPLEVEL_REF:
  657. if (SCM_VARIABLEP (mx))
  658. return mx;
  659. else
  660. {
  661. SCM var = scm_module_variable (mod, mx);
  662. if (scm_is_false (var) || scm_is_false (scm_variable_bound_p (var)))
  663. error_unbound_variable (mx);
  664. SCM_SETCDR (m, var);
  665. return var;
  666. }
  667. case SCM_M_TOPLEVEL_SET:
  668. {
  669. SCM var = CAR (mx);
  670. if (SCM_VARIABLEP (var))
  671. return var;
  672. else
  673. {
  674. var = scm_module_variable (mod, var);
  675. if (scm_is_false (var))
  676. error_unbound_variable (CAR (mx));
  677. SCM_SETCAR (mx, var);
  678. return var;
  679. }
  680. }
  681. case SCM_M_MODULE_REF:
  682. if (SCM_VARIABLEP (mx))
  683. return mx;
  684. else
  685. {
  686. SCM var;
  687. mod = scm_resolve_module (CAR (mx));
  688. if (scm_is_true (CDDR (mx)))
  689. mod = scm_module_public_interface (mod);
  690. var = scm_module_lookup (mod, CADR (mx));
  691. if (scm_is_false (scm_variable_bound_p (var)))
  692. error_unbound_variable (CADR (mx));
  693. SCM_SETCDR (m, var);
  694. return var;
  695. }
  696. case SCM_M_MODULE_SET:
  697. /* FIXME: not quite threadsafe */
  698. if (SCM_VARIABLEP (CDR (mx)))
  699. return CDR (mx);
  700. else
  701. {
  702. SCM var;
  703. mod = scm_resolve_module (CADR (mx));
  704. if (scm_is_true (CDDDR (mx)))
  705. mod = scm_module_public_interface (mod);
  706. var = scm_module_lookup (mod, CADDR (mx));
  707. SCM_SETCDR (mx, var);
  708. return var;
  709. }
  710. default:
  711. scm_wrong_type_arg (FUNC_NAME, 1, m);
  712. return SCM_BOOL_F;
  713. }
  714. }
  715. #undef FUNC_NAME
  716. void
  717. scm_init_memoize ()
  718. {
  719. #include "libguile/memoize.x"
  720. wind = scm_c_make_gsubr ("wind", 2, 0, 0, do_wind);
  721. unwind = scm_c_make_gsubr ("unwind", 0, 0, 0, do_unwind);
  722. push_fluid = scm_c_make_gsubr ("push-fluid", 2, 0, 0, do_push_fluid);
  723. pop_fluid = scm_c_make_gsubr ("pop-fluid", 0, 0, 0, do_pop_fluid);
  724. list_of_guile = scm_list_1 (scm_from_latin1_symbol ("guile"));
  725. }
  726. /*
  727. Local Variables:
  728. c-file-style: "gnu"
  729. End:
  730. */