scm_memoize_lambda update
[bpt/guile.git] / libguile / memoize.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
2 * Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20 \f
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "libguile/__scm.h"
27 #include "libguile/_scm.h"
28 #include "libguile/continuations.h"
29 #include "libguile/eq.h"
30 #include "libguile/list.h"
31 #include "libguile/macros.h"
32 #include "libguile/memoize.h"
33 #include "libguile/modules.h"
34 #include "libguile/srcprop.h"
35 #include "libguile/ports.h"
36 #include "libguile/print.h"
37 #include "libguile/strings.h"
38 #include "libguile/throw.h"
39 #include "libguile/validate.h"
40
41
42 \f
43
44
45 #define CAR(x) SCM_CAR(x)
46 #define CDR(x) SCM_CDR(x)
47 #define CAAR(x) SCM_CAAR(x)
48 #define CADR(x) SCM_CADR(x)
49 #define CDAR(x) SCM_CDAR(x)
50 #define CDDR(x) SCM_CDDR(x)
51 #define CADDR(x) SCM_CADDR(x)
52 #define CDDDR(x) SCM_CDDDR(x)
53 #define CADDDR(x) SCM_CADDDR(x)
54
55
56 static const char s_bad_expression[] = "Bad expression";
57 static const char s_expression[] = "Missing or extra expression in";
58 static const char s_missing_expression[] = "Missing expression in";
59 static const char s_extra_expression[] = "Extra expression in";
60 static const char s_empty_combination[] = "Illegal empty combination";
61 static const char s_missing_body_expression[] = "Missing body expression in";
62 static const char s_mixed_body_forms[] = "Mixed definitions and expressions in";
63 static const char s_bad_define[] = "Bad define placement";
64 static const char s_missing_clauses[] = "Missing clauses";
65 static const char s_misplaced_else_clause[] = "Misplaced else clause";
66 static const char s_bad_case_clause[] = "Bad case clause";
67 static const char s_bad_case_labels[] = "Bad case labels";
68 static const char s_duplicate_case_label[] = "Duplicate case label";
69 static const char s_bad_cond_clause[] = "Bad cond clause";
70 static const char s_missing_recipient[] = "Missing recipient in";
71 static const char s_bad_variable[] = "Bad variable";
72 static const char s_bad_bindings[] = "Bad bindings";
73 static const char s_bad_binding[] = "Bad binding";
74 static const char s_duplicate_binding[] = "Duplicate binding";
75 static const char s_bad_exit_clause[] = "Bad exit clause";
76 static const char s_bad_formals[] = "Bad formals";
77 static const char s_bad_formal[] = "Bad formal";
78 static const char s_duplicate_formal[] = "Duplicate formal";
79 static const char s_splicing[] = "Non-list result for unquote-splicing";
80 static const char s_bad_slot_number[] = "Bad slot number";
81
82
83 /* Signal a syntax error. We distinguish between the form that caused the
84 * error and the enclosing expression. The error message will print out as
85 * shown in the following pattern. The file name and line number are only
86 * given when they can be determined from the erroneous form or from the
87 * enclosing expression.
88 *
89 * <filename>: In procedure memoization:
90 * <filename>: In file <name>, line <nr>: <error-message> in <expression>. */
91
92 SCM_SYMBOL (syntax_error_key, "syntax-error");
93
94 /* The prototype is needed to indicate that the function does not return. */
95 static void
96 syntax_error (const char* const, const SCM, const SCM) SCM_NORETURN;
97
98 static void
99 syntax_error (const char* const msg, const SCM form, const SCM expr)
100 {
101 SCM msg_string = scm_from_locale_string (msg);
102 SCM filename = SCM_BOOL_F;
103 SCM linenr = SCM_BOOL_F;
104 const char *format;
105 SCM args;
106
107 if (scm_is_pair (form))
108 {
109 filename = scm_source_property (form, scm_sym_filename);
110 linenr = scm_source_property (form, scm_sym_line);
111 }
112
113 if (scm_is_false (filename) && scm_is_false (linenr) && scm_is_pair (expr))
114 {
115 filename = scm_source_property (expr, scm_sym_filename);
116 linenr = scm_source_property (expr, scm_sym_line);
117 }
118
119 if (!SCM_UNBNDP (expr))
120 {
121 if (scm_is_true (filename))
122 {
123 format = "In file ~S, line ~S: ~A ~S in expression ~S.";
124 args = scm_list_5 (filename, linenr, msg_string, form, expr);
125 }
126 else if (scm_is_true (linenr))
127 {
128 format = "In line ~S: ~A ~S in expression ~S.";
129 args = scm_list_4 (linenr, msg_string, form, expr);
130 }
131 else
132 {
133 format = "~A ~S in expression ~S.";
134 args = scm_list_3 (msg_string, form, expr);
135 }
136 }
137 else
138 {
139 if (scm_is_true (filename))
140 {
141 format = "In file ~S, line ~S: ~A ~S.";
142 args = scm_list_4 (filename, linenr, msg_string, form);
143 }
144 else if (scm_is_true (linenr))
145 {
146 format = "In line ~S: ~A ~S.";
147 args = scm_list_3 (linenr, msg_string, form);
148 }
149 else
150 {
151 format = "~A ~S.";
152 args = scm_list_2 (msg_string, form);
153 }
154 }
155
156 scm_error (syntax_error_key, "memoization", format, args, SCM_BOOL_F);
157 }
158
159
160 /* Shortcut macros to simplify syntax error handling. */
161 #define ASSERT_SYNTAX(cond, message, form) \
162 { if (SCM_UNLIKELY (!(cond))) \
163 syntax_error (message, form, SCM_UNDEFINED); }
164 #define ASSERT_SYNTAX_2(cond, message, form, expr) \
165 { if (SCM_UNLIKELY (!(cond))) \
166 syntax_error (message, form, expr); }
167
168 \f
169
170
171 /* {Evaluator memoized expressions}
172 */
173
174 scm_t_bits scm_tc16_memoized;
175
176 #define MAKMEMO(n, args) (scm_cell (scm_tc16_memoized | ((n) << 16), (scm_t_bits)(args)))
177
178 #define MAKMEMO_BEGIN(exps) \
179 MAKMEMO (SCM_M_BEGIN, exps)
180 #define MAKMEMO_IF(test, then, else_) \
181 MAKMEMO (SCM_M_IF, scm_cons (test, scm_cons (then, else_)))
182 #define FIXED_ARITY(nreq) \
183 scm_list_1 (SCM_I_MAKINUM (nreq))
184 #define REST_ARITY(nreq, rest) \
185 scm_list_2 (SCM_I_MAKINUM (nreq), rest)
186 #define FULL_ARITY(nreq, rest, nopt, kw, inits, alt) \
187 scm_list_n (SCM_I_MAKINUM (nreq), rest, SCM_I_MAKINUM (nopt), kw, inits, \
188 alt, SCM_UNDEFINED)
189 #define MAKMEMO_LAMBDA(body, arity) \
190 MAKMEMO (SCM_M_LAMBDA, (scm_cons (body, arity)))
191 #define MAKMEMO_LET(inits, body) \
192 MAKMEMO (SCM_M_LET, scm_cons (inits, body))
193 #define MAKMEMO_QUOTE(exp) \
194 MAKMEMO (SCM_M_QUOTE, exp)
195 #define MAKMEMO_DEFINE(var, val) \
196 MAKMEMO (SCM_M_DEFINE, scm_cons (var, val))
197 #define MAKMEMO_DYNWIND(in, expr, out) \
198 MAKMEMO (SCM_M_DYNWIND, scm_cons (in, scm_cons (expr, out)))
199 #define MAKMEMO_WITH_FLUIDS(fluids, vals, expr) \
200 MAKMEMO (SCM_M_WITH_FLUIDS, scm_cons (fluids, scm_cons (vals, expr)))
201 #define MAKMEMO_APPLY(proc, args)\
202 MAKMEMO (SCM_M_APPLY, scm_list_2 (proc, args))
203 #define MAKMEMO_CONT(proc) \
204 MAKMEMO (SCM_M_CONT, proc)
205 #define MAKMEMO_CALL_WITH_VALUES(prod, cons) \
206 MAKMEMO (SCM_M_CALL_WITH_VALUES, scm_cons (prod, cons))
207 #define MAKMEMO_CALL(proc, nargs, args) \
208 MAKMEMO (SCM_M_CALL, scm_cons (proc, scm_cons (SCM_I_MAKINUM (nargs), args)))
209 #define MAKMEMO_LEX_REF(n) \
210 MAKMEMO (SCM_M_LEXICAL_REF, SCM_I_MAKINUM (n))
211 #define MAKMEMO_LEX_SET(n, val) \
212 MAKMEMO (SCM_M_LEXICAL_SET, scm_cons (SCM_I_MAKINUM (n), val))
213 #define MAKMEMO_TOP_REF(var) \
214 MAKMEMO (SCM_M_TOPLEVEL_REF, var)
215 #define MAKMEMO_TOP_SET(var, val) \
216 MAKMEMO (SCM_M_TOPLEVEL_SET, scm_cons (var, val))
217 #define MAKMEMO_MOD_REF(mod, var, public) \
218 MAKMEMO (SCM_M_MODULE_REF, scm_cons (mod, scm_cons (var, public)))
219 #define MAKMEMO_MOD_SET(val, mod, var, public) \
220 MAKMEMO (SCM_M_MODULE_SET, scm_cons (val, scm_cons (mod, scm_cons (var, public))))
221 #define MAKMEMO_PROMPT(tag, exp, handler) \
222 MAKMEMO (SCM_M_PROMPT, scm_cons (tag, scm_cons (exp, handler)))
223
224
225 /* Primitives for the evaluator */
226 scm_t_bits scm_tc16_memoizer;
227 #define SCM_MEMOIZER_P(x) (SCM_SMOB_PREDICATE (scm_tc16_memoizer, (x)))
228 #define SCM_MEMOIZER(M) (SCM_SMOB_OBJECT_1 (M))
229
230 \f
231
232 /* This table must agree with the list of M_ constants in memoize.h */
233 static const char *const memoized_tags[] =
234 {
235 "begin",
236 "if",
237 "lambda",
238 "let",
239 "quote",
240 "define",
241 "dynwind",
242 "with-fluids",
243 "apply",
244 "call/cc",
245 "call-with-values",
246 "call",
247 "lexical-ref",
248 "lexical-set!",
249 "toplevel-ref",
250 "toplevel-set!",
251 "module-ref",
252 "module-set!",
253 "prompt",
254 };
255
256 static int
257 scm_print_memoized (SCM memoized, SCM port, scm_print_state *pstate)
258 {
259 scm_puts ("#<memoized ", port);
260 scm_write (scm_unmemoize_expression (memoized), port);
261 scm_puts (">", port);
262 return 1;
263 }
264
265 static SCM scm_m_at (SCM xorig, SCM env);
266 static SCM scm_m_atat (SCM xorig, SCM env);
267 static SCM scm_m_and (SCM xorig, SCM env);
268 static SCM scm_m_begin (SCM xorig, SCM env);
269 static SCM scm_m_cond (SCM xorig, SCM env);
270 static SCM scm_m_define (SCM x, SCM env);
271 static SCM scm_m_with_fluids (SCM xorig, SCM env);
272 static SCM scm_m_eval_when (SCM xorig, SCM env);
273 static SCM scm_m_if (SCM xorig, SCM env);
274 static SCM scm_m_lambda (SCM xorig, SCM env);
275 static SCM scm_m_lambda_star (SCM xorig, SCM env);
276 static SCM scm_m_case_lambda (SCM xorig, SCM env);
277 static SCM scm_m_case_lambda_star (SCM xorig, SCM env);
278 static SCM scm_m_let (SCM xorig, SCM env);
279 static SCM scm_m_letrec (SCM xorig, SCM env);
280 static SCM scm_m_letstar (SCM xorig, SCM env);
281 static SCM scm_m_or (SCM xorig, SCM env);
282 static SCM scm_m_quote (SCM xorig, SCM env);
283 static SCM scm_m_set_x (SCM xorig, SCM env);
284
285 \f
286
287
288 static SCM
289 memoize_env_ref_macro (SCM env, SCM x)
290 {
291 SCM var;
292 for (; scm_is_pair (env); env = CDR (env))
293 if (scm_is_eq (x, CAR (env)))
294 return SCM_BOOL_F; /* lexical */
295
296 var = scm_module_variable (env, x);
297 if (scm_is_true (var) && scm_is_true (scm_variable_bound_p (var))
298 && (scm_is_true (scm_macro_p (scm_variable_ref (var)))
299 || SCM_MEMOIZER_P (scm_variable_ref (var))))
300 return scm_variable_ref (var);
301 else
302 return SCM_BOOL_F; /* anything else */
303 }
304
305 static int
306 memoize_env_var_is_free (SCM env, SCM x)
307 {
308 for (; scm_is_pair (env); env = CDR (env))
309 if (scm_is_eq (x, CAR (env)))
310 return 0; /* bound */
311 return 1; /* free */
312 }
313
314 static int
315 memoize_env_lexical_index (SCM env, SCM x)
316 {
317 int i = 0;
318 for (; scm_is_pair (env); env = CDR (env), i++)
319 if (scm_is_eq (x, CAR (env)))
320 return i; /* bound */
321 return -1; /* free */
322 }
323
324 static SCM
325 memoize_env_extend (SCM env, SCM vars)
326 {
327 return scm_append (scm_list_2 (vars, env));
328 }
329
330 static SCM
331 memoize (SCM exp, SCM env)
332 {
333 if (scm_is_pair (exp))
334 {
335 SCM car;
336 scm_t_macro_primitive trans = NULL;
337 SCM macro = SCM_BOOL_F, memoizer = SCM_BOOL_F;
338
339 car = CAR (exp);
340 if (scm_is_symbol (car))
341 macro = memoize_env_ref_macro (env, car);
342
343 if (scm_is_true (scm_macro_p (macro)))
344 trans = scm_i_macro_primitive (macro);
345 else if (SCM_MEMOIZER_P (macro))
346 memoizer = SCM_MEMOIZER (macro);
347
348 if (trans)
349 return trans (exp, env);
350 else
351 {
352 SCM args = SCM_EOL;
353 int nargs = 0;
354 SCM proc = CAR (exp);
355
356 for (exp = CDR (exp); scm_is_pair (exp); exp = CDR (exp), nargs++)
357 args = scm_cons (memoize (CAR (exp), env), args);
358 if (scm_is_null (exp))
359 {
360 if (scm_is_true (memoizer))
361 return scm_apply (memoizer, scm_reverse_x (args, SCM_UNDEFINED),
362 SCM_EOL);
363 else
364 return MAKMEMO_CALL (memoize (proc, env),
365 nargs,
366 scm_reverse_x (args, SCM_UNDEFINED));
367 }
368
369 else
370 syntax_error ("expected a proper list", exp, SCM_UNDEFINED);
371 }
372 }
373 else if (scm_is_symbol (exp))
374 {
375 int i = memoize_env_lexical_index (env, exp);
376 if (i < 0)
377 return MAKMEMO_TOP_REF (exp);
378 else
379 return MAKMEMO_LEX_REF (i);
380 }
381 else
382 return MAKMEMO_QUOTE (exp);
383 }
384
385 static SCM
386 memoize_exprs (SCM forms, const SCM env)
387 {
388 SCM ret = SCM_EOL;
389
390 for (; !scm_is_null (forms); forms = CDR (forms))
391 ret = scm_cons (memoize (CAR (forms), env), ret);
392 return scm_reverse_x (ret, SCM_UNDEFINED);
393 }
394
395 static SCM
396 memoize_sequence (const SCM forms, const SCM env)
397 {
398 ASSERT_SYNTAX (scm_ilength (forms) >= 1, s_bad_expression,
399 scm_cons (scm_sym_begin, forms));
400 if (scm_is_null (CDR (forms)))
401 return memoize (CAR (forms), env);
402 else
403 return MAKMEMO_BEGIN (memoize_exprs (forms, env));
404 }
405
406
407 \f
408 /* Memoization. */
409
410 #define SCM_SYNTAX(RANAME, STR, CFN) \
411 SCM_SNARF_HERE(static const char RANAME[]=STR)\
412 SCM_SNARF_INIT(scm_c_define (RANAME, scm_i_make_primitive_macro (RANAME, CFN)))
413
414
415 /* True primitive syntax */
416 SCM_SYNTAX (s_at, "@", scm_m_at);
417 SCM_SYNTAX (s_atat, "@@", scm_m_atat);
418 SCM_SYNTAX (s_begin, "begin", scm_m_begin);
419 SCM_SYNTAX (s_define, "define", scm_m_define);
420 SCM_SYNTAX (s_with_fluids, "with-fluids", scm_m_with_fluids);
421 SCM_SYNTAX (s_eval_when, "eval-when", scm_m_eval_when);
422 SCM_SYNTAX (s_if, "if", scm_m_if);
423 SCM_SYNTAX (s_lambda, "lambda", scm_m_lambda);
424 SCM_SYNTAX (s_let, "let", scm_m_let);
425 SCM_SYNTAX (s_quote, "quote", scm_m_quote);
426 SCM_SYNTAX (s_set_x, "set!", scm_m_set_x);
427
428 /* Convenient syntax during boot, expands to primitive syntax. Replaced after
429 psyntax boots. */
430 SCM_SYNTAX (s_and, "and", scm_m_and);
431 SCM_SYNTAX (s_cond, "cond", scm_m_cond);
432 SCM_SYNTAX (s_letrec, "letrec", scm_m_letrec);
433 SCM_SYNTAX (s_letstar, "let*", scm_m_letstar);
434 SCM_SYNTAX (s_or, "or", scm_m_or);
435 SCM_SYNTAX (s_lambda_star, "lambda*", scm_m_lambda_star);
436 SCM_SYNTAX (s_case_lambda, "case-lambda", scm_m_case_lambda);
437 SCM_SYNTAX (s_case_lambda_star, "case-lambda*", scm_m_case_lambda_star);
438
439 SCM_GLOBAL_SYMBOL (scm_sym_apply, "apply");
440 SCM_GLOBAL_SYMBOL (scm_sym_arrow, "=>");
441 SCM_GLOBAL_SYMBOL (scm_sym_at, "@");
442 SCM_GLOBAL_SYMBOL (scm_sym_atat, "@@");
443 SCM_GLOBAL_SYMBOL (scm_sym_at_call_with_values, "@call-with-values");
444 SCM_GLOBAL_SYMBOL (scm_sym_atapply, "@apply");
445 SCM_GLOBAL_SYMBOL (scm_sym_atcall_cc, "@call-with-current-continuation");
446 SCM_GLOBAL_SYMBOL (scm_sym_begin, "begin");
447 SCM_GLOBAL_SYMBOL (scm_sym_case, "case");
448 SCM_GLOBAL_SYMBOL (scm_sym_cond, "cond");
449 SCM_GLOBAL_SYMBOL (scm_sym_define, "define");
450 SCM_GLOBAL_SYMBOL (scm_sym_at_dynamic_wind, "@dynamic-wind");
451 SCM_GLOBAL_SYMBOL (scm_sym_with_fluids, "with-fluids");
452 SCM_GLOBAL_SYMBOL (scm_sym_else, "else");
453 SCM_GLOBAL_SYMBOL (scm_sym_eval_when, "eval-when");
454 SCM_GLOBAL_SYMBOL (scm_sym_if, "if");
455 SCM_GLOBAL_SYMBOL (scm_sym_lambda, "lambda");
456 SCM_GLOBAL_SYMBOL (scm_sym_let, "let");
457 SCM_GLOBAL_SYMBOL (scm_sym_letrec, "letrec");
458 SCM_GLOBAL_SYMBOL (scm_sym_letstar, "let*");
459 SCM_GLOBAL_SYMBOL (scm_sym_or, "or");
460 SCM_GLOBAL_SYMBOL (scm_sym_at_prompt, "@prompt");
461 SCM_GLOBAL_SYMBOL (scm_sym_quote, "quote");
462 SCM_GLOBAL_SYMBOL (scm_sym_set_x, "set!");
463 SCM_SYMBOL (sym_lambda_star, "lambda*");
464 SCM_SYMBOL (sym_case_lambda, "case-lambda");
465 SCM_SYMBOL (sym_case_lambda_star, "case-lambda*");
466 SCM_SYMBOL (sym_eval, "eval");
467 SCM_SYMBOL (sym_load, "load");
468
469 SCM_GLOBAL_SYMBOL (scm_sym_unquote, "unquote");
470 SCM_GLOBAL_SYMBOL (scm_sym_quasiquote, "quasiquote");
471 SCM_GLOBAL_SYMBOL (scm_sym_uq_splicing, "unquote-splicing");
472
473 SCM_KEYWORD (kw_allow_other_keys, "allow-other-keys");
474 SCM_KEYWORD (kw_optional, "optional");
475 SCM_KEYWORD (kw_key, "key");
476 SCM_KEYWORD (kw_rest, "rest");
477
478
479 static SCM
480 scm_m_at (SCM expr, SCM env SCM_UNUSED)
481 {
482 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
483 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
484 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
485
486 return MAKMEMO_MOD_REF (CADR (expr), CADDR (expr), SCM_BOOL_T);
487 }
488
489 static SCM
490 scm_m_atat (SCM expr, SCM env SCM_UNUSED)
491 {
492 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
493 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
494 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
495
496 return MAKMEMO_MOD_REF (CADR (expr), CADDR (expr), SCM_BOOL_F);
497 }
498
499 static SCM
500 scm_m_and (SCM expr, SCM env)
501 {
502 const SCM cdr_expr = CDR (expr);
503
504 if (scm_is_null (cdr_expr))
505 return MAKMEMO_QUOTE (SCM_BOOL_T);
506 ASSERT_SYNTAX (scm_is_pair (cdr_expr), s_bad_expression, expr);
507
508 if (scm_is_null (CDR (cdr_expr)))
509 return memoize (CAR (cdr_expr), env);
510 else
511 return MAKMEMO_IF (memoize (CAR (cdr_expr), env),
512 scm_m_and (cdr_expr, env),
513 MAKMEMO_QUOTE (SCM_BOOL_F));
514 }
515
516 static SCM
517 scm_m_begin (SCM expr, SCM env)
518 {
519 const SCM cdr_expr = CDR (expr);
520 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 1, s_bad_expression, expr);
521 return MAKMEMO_BEGIN (memoize_exprs (cdr_expr, env));
522 }
523
524 static SCM
525 scm_m_cond (SCM expr, SCM env)
526 {
527 /* Check, whether 'else or '=> is a literal, i. e. not bound to a value. */
528 const int else_literal_p = memoize_env_var_is_free (env, scm_sym_else);
529 const int arrow_literal_p = memoize_env_var_is_free (env, scm_sym_arrow);
530
531 const SCM clauses = CDR (expr);
532 SCM clause_idx;
533 SCM ret, loc;
534
535 ASSERT_SYNTAX (scm_ilength (clauses) >= 0, s_bad_expression, expr);
536 ASSERT_SYNTAX (scm_ilength (clauses) >= 1, s_missing_clauses, expr);
537
538 ret = scm_cons (SCM_UNDEFINED, MAKMEMO_QUOTE (SCM_UNSPECIFIED));
539 loc = ret;
540
541 for (clause_idx = clauses;
542 !scm_is_null (clause_idx);
543 clause_idx = CDR (clause_idx))
544 {
545 SCM test;
546
547 const SCM clause = CAR (clause_idx);
548 const long length = scm_ilength (clause);
549 ASSERT_SYNTAX_2 (length >= 1, s_bad_cond_clause, clause, expr);
550
551 test = CAR (clause);
552 if (scm_is_eq (test, scm_sym_else) && else_literal_p)
553 {
554 const int last_clause_p = scm_is_null (CDR (clause_idx));
555 ASSERT_SYNTAX_2 (length >= 2,
556 s_bad_cond_clause, clause, expr);
557 ASSERT_SYNTAX_2 (last_clause_p,
558 s_misplaced_else_clause, clause, expr);
559 SCM_SETCDR (loc,
560 memoize (scm_cons (scm_sym_begin, CDR (clause)), env));
561 }
562 else if (length >= 2
563 && scm_is_eq (CADR (clause), scm_sym_arrow)
564 && arrow_literal_p)
565 {
566 SCM tmp = scm_gensym (scm_from_locale_string ("cond "));
567 SCM i;
568 SCM new_env = scm_cons (tmp, env);
569 ASSERT_SYNTAX_2 (length > 2, s_missing_recipient, clause, expr);
570 ASSERT_SYNTAX_2 (length == 3, s_extra_expression, clause, expr);
571 i = MAKMEMO_IF (MAKMEMO_LEX_REF (0),
572 MAKMEMO_CALL (memoize (CADDR (clause),
573 scm_cons (tmp, new_env)),
574 1,
575 scm_list_1 (MAKMEMO_LEX_REF (0))),
576 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
577 SCM_SETCDR (loc,
578 MAKMEMO_LET (scm_list_1 (memoize (CAR (clause), env)),
579 i));
580 env = new_env;
581 loc = scm_last_pair (SCM_MEMOIZED_ARGS (i));
582 }
583 /* FIXME length == 1 case */
584 else
585 {
586 SCM i = MAKMEMO_IF (memoize (CAR (clause), env),
587 memoize (scm_cons (scm_sym_begin, CDR (clause)), env),
588 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
589 SCM_SETCDR (loc, i);
590 loc = scm_last_pair (SCM_MEMOIZED_ARGS (i));
591 }
592 }
593
594 return CDR (ret);
595 }
596
597 /* According to Section 5.2.1 of R5RS we first have to make sure that the
598 variable is bound, and then perform the `(set! variable expression)'
599 operation. However, EXPRESSION _can_ be evaluated before VARIABLE is
600 bound. This means that EXPRESSION won't necessarily be able to assign
601 values to VARIABLE as in `(define foo (begin (set! foo 1) (+ foo 1)))'. */
602 static SCM
603 scm_m_define (SCM expr, SCM env)
604 {
605 const SCM cdr_expr = CDR (expr);
606 SCM body;
607 SCM variable;
608
609 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
610 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
611 ASSERT_SYNTAX (!scm_is_pair (env), s_bad_define, expr);
612
613 body = CDR (cdr_expr);
614 variable = CAR (cdr_expr);
615
616 if (scm_is_pair (variable))
617 {
618 ASSERT_SYNTAX_2 (scm_is_symbol (CAR (variable)), s_bad_variable, variable, expr);
619 return MAKMEMO_DEFINE (CAR (variable),
620 memoize (scm_cons (scm_sym_lambda,
621 scm_cons (CDR (variable), body)),
622 env));
623 }
624 ASSERT_SYNTAX_2 (scm_is_symbol (variable), s_bad_variable, variable, expr);
625 ASSERT_SYNTAX (scm_ilength (body) == 1, s_expression, expr);
626 return MAKMEMO_DEFINE (variable, memoize (CAR (body), env));
627 }
628
629 static SCM
630 scm_m_with_fluids (SCM expr, SCM env)
631 {
632 SCM binds, fluids, vals;
633 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
634 binds = CADR (expr);
635 ASSERT_SYNTAX_2 (scm_ilength (binds) >= 0, s_bad_bindings, binds, expr);
636 for (fluids = SCM_EOL, vals = SCM_EOL;
637 scm_is_pair (binds);
638 binds = CDR (binds))
639 {
640 SCM binding = CAR (binds);
641 ASSERT_SYNTAX_2 (scm_ilength (CAR (binds)) == 2, s_bad_binding,
642 binding, expr);
643 fluids = scm_cons (memoize (CAR (binding), env), fluids);
644 vals = scm_cons (memoize (CADR (binding), env), vals);
645 }
646
647 return MAKMEMO_WITH_FLUIDS (scm_reverse_x (fluids, SCM_UNDEFINED),
648 scm_reverse_x (vals, SCM_UNDEFINED),
649 memoize_sequence (CDDR (expr), env));
650 }
651
652 static SCM
653 scm_m_eval_when (SCM expr, SCM env)
654 {
655 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
656 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
657
658 if (scm_is_true (scm_memq (sym_eval, CADR (expr)))
659 || scm_is_true (scm_memq (sym_load, CADR (expr))))
660 return MAKMEMO_BEGIN (memoize_exprs (CDDR (expr), env));
661 else
662 return MAKMEMO_QUOTE (SCM_UNSPECIFIED);
663 }
664
665 static SCM
666 scm_m_if (SCM expr, SCM env SCM_UNUSED)
667 {
668 const SCM cdr_expr = CDR (expr);
669 const long length = scm_ilength (cdr_expr);
670 ASSERT_SYNTAX (length == 2 || length == 3, s_expression, expr);
671 return MAKMEMO_IF (memoize (CADR (expr), env),
672 memoize (CADDR (expr), env),
673 ((length == 3)
674 ? memoize (CADDDR (expr), env)
675 : MAKMEMO_QUOTE (SCM_UNSPECIFIED)));
676 }
677
678 /* A helper function for memoize_lambda to support checking for duplicate
679 * formal arguments: Return true if OBJ is `eq?' to one of the elements of
680 * LIST or to the CDR of the last cons. Therefore, LIST may have any of the
681 * forms that a formal argument can have:
682 * <rest>, (<arg1> ...), (<arg1> ... . <rest>) */
683 static int
684 c_improper_memq (SCM obj, SCM list)
685 {
686 for (; scm_is_pair (list); list = CDR (list))
687 {
688 if (scm_is_eq (CAR (list), obj))
689 return 1;
690 }
691 return scm_is_eq (list, obj);
692 }
693
694 static SCM
695 scm_m_lambda (SCM expr, SCM env SCM_UNUSED)
696 {
697 SCM formals;
698 SCM formals_idx;
699 SCM formal_vars = SCM_EOL;
700 SCM body;
701 int nreq = 0;
702
703 const SCM cdr_expr = CDR (expr);
704 const long length = scm_ilength (cdr_expr);
705 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
706 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
707
708 /* Before iterating the list of formal arguments, make sure the formals
709 * actually are given as either a symbol or a non-cyclic list. */
710 formals = CAR (cdr_expr);
711 if (scm_is_pair (formals))
712 {
713 /* Dirk:FIXME:: We should check for a cyclic list of formals, and if
714 * detected, report a 'Bad formals' error. */
715 }
716 else
717 {
718 ASSERT_SYNTAX_2 (scm_is_symbol (formals) || scm_is_null (formals),
719 s_bad_formals, formals, expr);
720 }
721
722 /* Now iterate the list of formal arguments to check if all formals are
723 * symbols, and that there are no duplicates. */
724 formals_idx = formals;
725 while (scm_is_pair (formals_idx))
726 {
727 const SCM formal = CAR (formals_idx);
728 const SCM next_idx = CDR (formals_idx);
729 ASSERT_SYNTAX_2 (scm_is_symbol (formal), s_bad_formal, formal, expr);
730 ASSERT_SYNTAX_2 (!c_improper_memq (formal, next_idx),
731 s_duplicate_formal, formal, expr);
732 nreq++;
733 formal_vars = scm_cons (formal, formal_vars);
734 formals_idx = next_idx;
735 }
736 ASSERT_SYNTAX_2 (scm_is_null (formals_idx) || scm_is_symbol (formals_idx),
737 s_bad_formal, formals_idx, expr);
738 if (scm_is_symbol (formals_idx))
739 formal_vars = scm_cons (formals_idx, formal_vars);
740
741 body = memoize_sequence (CDDR (expr), memoize_env_extend (env, formal_vars));
742
743 if (scm_is_symbol (formals_idx))
744 return MAKMEMO_LAMBDA (body, REST_ARITY (nreq, SCM_BOOL_T));
745 else
746 return MAKMEMO_LAMBDA (body, FIXED_ARITY (nreq));
747 }
748
749 static SCM
750 scm_m_lambda_star (SCM expr, SCM env)
751 {
752 SCM req, opt, kw, allow_other_keys, rest, formals, body;
753 SCM inits, kw_indices;
754 int nreq, nopt;
755
756 const long length = scm_ilength (expr);
757 ASSERT_SYNTAX (length >= 1, s_bad_expression, expr);
758 ASSERT_SYNTAX (length >= 3, s_missing_expression, expr);
759
760 formals = CADR (expr);
761 body = CDDR (expr);
762
763 nreq = nopt = 0;
764 req = opt = kw = SCM_EOL;
765 rest = allow_other_keys = SCM_BOOL_F;
766
767 while (scm_is_pair (formals) && scm_is_symbol (CAR (formals)))
768 {
769 nreq++;
770 req = scm_cons (CAR (formals), req);
771 formals = scm_cdr (formals);
772 }
773
774 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_optional))
775 {
776 formals = CDR (formals);
777 while (scm_is_pair (formals)
778 && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals))))
779 {
780 nopt++;
781 opt = scm_cons (CAR (formals), opt);
782 formals = scm_cdr (formals);
783 }
784 }
785
786 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_key))
787 {
788 formals = CDR (formals);
789 while (scm_is_pair (formals)
790 && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals))))
791 {
792 kw = scm_cons (CAR (formals), kw);
793 formals = scm_cdr (formals);
794 }
795 }
796
797 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_allow_other_keys))
798 {
799 formals = CDR (formals);
800 allow_other_keys = SCM_BOOL_T;
801 }
802
803 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_rest))
804 {
805 if (scm_ilength (formals) != 2)
806 syntax_error (s_bad_formals, CADR (expr), expr);
807 else
808 rest = CADR (formals);
809 }
810 else if (scm_is_symbol (formals))
811 rest = formals;
812 else if (!scm_is_null (formals))
813 syntax_error (s_bad_formals, CADR (expr), expr);
814 else
815 rest = SCM_BOOL_F;
816
817 /* Now, iterate through them a second time, building up an expansion-time
818 environment, checking, expanding and canonicalizing the opt/kw init forms,
819 and eventually memoizing the body as well. Note that the rest argument, if
820 any, is expanded before keyword args, thus necessitating the second
821 pass.
822
823 Also note that the specific environment during expansion of init
824 expressions here needs to coincide with the environment when psyntax
825 expands. A lot of effort for something that is only used in the bootstrap
826 memoizer, you say? Yes. Yes it is.
827 */
828
829 inits = SCM_EOL;
830
831 /* nreq is already set, and req is already reversed: simply extend. */
832 env = memoize_env_extend (env, req);
833
834 /* Build up opt inits and env */
835 opt = scm_reverse_x (opt, SCM_EOL);
836 while (scm_is_pair (opt))
837 {
838 SCM x = CAR (opt);
839 if (scm_is_symbol (x))
840 inits = scm_cons (MAKMEMO_QUOTE (SCM_BOOL_F), inits);
841 else if (scm_ilength (x) == 2 && scm_is_symbol (CAR (x)))
842 inits = scm_cons (memoize (CADR (x), env), inits);
843 else
844 syntax_error (s_bad_formals, CADR (expr), expr);
845 env = scm_cons (scm_is_symbol (x) ? x : CAR (x), env);
846 opt = CDR (opt);
847 }
848
849 /* Process rest before keyword args */
850 if (scm_is_true (rest))
851 env = scm_cons (rest, env);
852
853 /* Build up kw inits, env, and kw-indices alist */
854 if (scm_is_null (kw))
855 kw_indices = SCM_BOOL_F;
856 else
857 {
858 int idx = nreq + nopt + (scm_is_true (rest) ? 1 : 0);
859
860 kw_indices = SCM_EOL;
861 kw = scm_reverse_x (kw, SCM_EOL);
862 while (scm_is_pair (kw))
863 {
864 SCM x, sym, k, init;
865 x = CAR (kw);
866 if (scm_is_symbol (x))
867 {
868 sym = x;
869 init = SCM_BOOL_F;
870 k = scm_symbol_to_keyword (sym);
871 }
872 else if (scm_ilength (x) == 2 && scm_is_symbol (CAR (x)))
873 {
874 sym = CAR (x);
875 init = CADR (x);
876 k = scm_symbol_to_keyword (sym);
877 }
878 else if (scm_ilength (x) == 3 && scm_is_symbol (CAR (x))
879 && scm_is_keyword (CADDR (x)))
880 {
881 sym = CAR (x);
882 init = CADR (x);
883 k = CADDR (x);
884 }
885 else
886 syntax_error (s_bad_formals, CADR (expr), expr);
887
888 kw_indices = scm_acons (k, SCM_I_MAKINUM (idx++), kw_indices);
889 inits = scm_cons (memoize (init, env), inits);
890 env = scm_cons (sym, env);
891 kw = CDR (kw);
892 }
893 kw_indices = scm_cons (allow_other_keys,
894 scm_reverse_x (kw_indices, SCM_UNDEFINED));
895 }
896
897 /* We should check for no duplicates, but given that psyntax does this
898 already, we can punt on it here... */
899
900 inits = scm_reverse_x (inits, SCM_UNDEFINED);
901 body = memoize_sequence (body, env);
902
903 if (scm_is_false (kw_indices) && scm_is_false (rest) && !nopt)
904 return MAKMEMO_LAMBDA (body, FIXED_ARITY (nreq));
905 if (scm_is_false (kw_indices) && !nopt)
906 return MAKMEMO_LAMBDA (body, REST_ARITY (nreq, SCM_BOOL_T));
907 else
908 return MAKMEMO_LAMBDA (body, FULL_ARITY (nreq, rest, nopt, kw_indices, inits,
909 SCM_BOOL_F));
910 }
911
912 static SCM
913 patch_case_lambda (SCM a, SCM b)
914 {
915 SCM mx, body, rest, kw_indices, inits;
916 int nreq, nopt;
917
918 mx = SCM_SMOB_OBJECT_1 (a);
919 body = CAR (mx);
920 mx = CDR (mx);
921
922 if (scm_is_null (CDR (mx)))
923 {
924 nreq = scm_to_int16 (CAR (mx));
925 rest = SCM_BOOL_F;
926 nopt = 0;
927 kw_indices = SCM_BOOL_F;
928 inits = SCM_EOL;
929 }
930 else if (scm_is_null (CDDR (mx)))
931 {
932 nreq = scm_to_int16 (CAR (mx));
933 rest = CADR (mx);
934 nopt = 0;
935 kw_indices = SCM_BOOL_F;
936 inits = SCM_EOL;
937 }
938 else
939 {
940 nreq = scm_to_int16 (CAR (mx));
941 rest = CADR (mx);
942 nopt = scm_to_int16 (CADDR (mx));
943 kw_indices = CADDDR (mx);
944 inits = CADR (CDDDR (mx));
945 }
946
947 return MAKMEMO_LAMBDA
948 (body, FULL_ARITY (nreq, rest, nopt, kw_indices, inits, b));
949 }
950
951 static SCM
952 scm_m_case_lambda (SCM expr, SCM env)
953 {
954 SCM ret, clauses;
955
956 const long length = scm_ilength (expr);
957 ASSERT_SYNTAX (length >= 1, s_bad_expression, expr);
958 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
959
960 clauses = scm_reverse (CDR (expr));
961 ret = SCM_BOOL_F;
962
963 for (; scm_is_pair (clauses); clauses = CDR (clauses))
964 ret = patch_case_lambda
965 (scm_m_lambda (scm_cons (scm_sym_lambda, CAR (clauses)), env), ret);
966
967 return ret;
968 }
969
970 static SCM
971 scm_m_case_lambda_star (SCM expr, SCM env)
972 {
973 SCM ret, clauses;
974
975 const long length = scm_ilength (expr);
976 ASSERT_SYNTAX (length >= 1, s_bad_expression, expr);
977 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
978
979 clauses = scm_reverse (CDR (expr));
980 ret = SCM_BOOL_F;
981
982 for (; scm_is_pair (clauses); clauses = CDR (clauses))
983 ret = patch_case_lambda
984 (scm_m_lambda_star (scm_cons (sym_lambda_star, CAR (clauses)), env), ret);
985
986 return ret;
987 }
988
989 /* Check if the format of the bindings is ((<symbol> <init-form>) ...). */
990 static void
991 check_bindings (const SCM bindings, const SCM expr)
992 {
993 SCM binding_idx;
994
995 ASSERT_SYNTAX_2 (scm_ilength (bindings) >= 0,
996 s_bad_bindings, bindings, expr);
997
998 binding_idx = bindings;
999 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
1000 {
1001 SCM name; /* const */
1002
1003 const SCM binding = CAR (binding_idx);
1004 ASSERT_SYNTAX_2 (scm_ilength (binding) == 2,
1005 s_bad_binding, binding, expr);
1006
1007 name = CAR (binding);
1008 ASSERT_SYNTAX_2 (scm_is_symbol (name), s_bad_variable, name, expr);
1009 }
1010 }
1011
1012 /* The bindings, which must have the format ((v1 i1) (v2 i2) ... (vn in)), are
1013 * transformed to the lists (vn .. v2 v1) and (i1 i2 ... in). If a duplicate
1014 * variable name is detected, an error is signalled. */
1015 static int
1016 transform_bindings (const SCM bindings, const SCM expr,
1017 SCM *const rvarptr, SCM *const initptr)
1018 {
1019 SCM rvariables = SCM_EOL;
1020 SCM rinits = SCM_EOL;
1021 SCM binding_idx = bindings;
1022 int n = 0;
1023 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
1024 {
1025 const SCM binding = CAR (binding_idx);
1026 const SCM CDR_binding = CDR (binding);
1027 const SCM name = CAR (binding);
1028 ASSERT_SYNTAX_2 (scm_is_false (scm_c_memq (name, rvariables)),
1029 s_duplicate_binding, name, expr);
1030 rvariables = scm_cons (name, rvariables);
1031 rinits = scm_cons (CAR (CDR_binding), rinits);
1032 n++;
1033 }
1034 *rvarptr = rvariables;
1035 *initptr = scm_reverse_x (rinits, SCM_UNDEFINED);
1036 return n;
1037 }
1038
1039 /* This function is a helper function for memoize_let. It transforms
1040 * (let name ((var init) ...) body ...) into
1041 * ((letrec ((name (lambda (var ...) body ...))) name) init ...)
1042 * and memoizes the expression. It is assumed that the caller has checked
1043 * that name is a symbol and that there are bindings and a body. */
1044 static SCM
1045 memoize_named_let (const SCM expr, SCM env)
1046 {
1047 SCM rvariables;
1048 SCM inits;
1049 int nreq;
1050
1051 const SCM cdr_expr = CDR (expr);
1052 const SCM name = CAR (cdr_expr);
1053 const SCM cddr_expr = CDR (cdr_expr);
1054 const SCM bindings = CAR (cddr_expr);
1055 check_bindings (bindings, expr);
1056
1057 nreq = transform_bindings (bindings, expr, &rvariables, &inits);
1058
1059 env = scm_cons (name, env);
1060 return MAKMEMO_LET
1061 (scm_list_1 (MAKMEMO_QUOTE (SCM_UNDEFINED)),
1062 MAKMEMO_BEGIN
1063 (scm_list_2 (MAKMEMO_LEX_SET
1064 (0,
1065 MAKMEMO_LAMBDA (memoize_sequence
1066 (CDDDR (expr),
1067 memoize_env_extend (env, rvariables)),
1068 FIXED_ARITY (nreq))),
1069 MAKMEMO_CALL (MAKMEMO_LEX_REF (0),
1070 nreq,
1071 memoize_exprs (inits, env)))));
1072 }
1073
1074 /* (let ((v1 i1) (v2 i2) ...) body) with variables v1 .. vn and initializers
1075 * i1 .. in is transformed to (#@let (vn ... v2 v1) (i1 i2 ...) body). */
1076 static SCM
1077 scm_m_let (SCM expr, SCM env)
1078 {
1079 SCM bindings;
1080
1081 const SCM cdr_expr = CDR (expr);
1082 const long length = scm_ilength (cdr_expr);
1083 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
1084 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
1085
1086 bindings = CAR (cdr_expr);
1087 if (scm_is_symbol (bindings))
1088 {
1089 ASSERT_SYNTAX (length >= 3, s_missing_expression, expr);
1090 return memoize_named_let (expr, env);
1091 }
1092
1093 check_bindings (bindings, expr);
1094 if (scm_is_null (bindings))
1095 return memoize_sequence (CDDR (expr), env);
1096 else
1097 {
1098 SCM rvariables;
1099 SCM inits;
1100 transform_bindings (bindings, expr, &rvariables, &inits);
1101 return MAKMEMO_LET (memoize_exprs (inits, env),
1102 memoize_sequence (CDDR (expr),
1103 memoize_env_extend (env, rvariables)));
1104 }
1105 }
1106
1107 static SCM
1108 scm_m_letrec (SCM expr, SCM env)
1109 {
1110 SCM bindings;
1111
1112 const SCM cdr_expr = CDR (expr);
1113 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1114 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
1115
1116 bindings = CAR (cdr_expr);
1117 if (scm_is_null (bindings))
1118 return memoize_sequence (CDDR (expr), env);
1119 else
1120 {
1121 SCM rvariables;
1122 SCM inits;
1123 SCM v, i;
1124 SCM undefs = SCM_EOL;
1125 SCM vals = SCM_EOL;
1126 SCM sets = SCM_EOL;
1127 SCM new_env;
1128 int offset;
1129 int n = transform_bindings (bindings, expr, &rvariables, &inits);
1130 offset = n;
1131 new_env = memoize_env_extend (env, rvariables);
1132 for (v = scm_reverse (rvariables), i = inits; scm_is_pair (v);
1133 v = CDR (v), i = CDR (i), n--)
1134 {
1135 undefs = scm_cons (MAKMEMO_QUOTE (SCM_UNDEFINED), undefs);
1136 vals = scm_cons (memoize (CAR (i), new_env), vals);
1137 sets = scm_cons (MAKMEMO_LEX_SET ((n-1) + offset,
1138 MAKMEMO_LEX_REF (n-1)),
1139 sets);
1140 }
1141 return MAKMEMO_LET
1142 (undefs,
1143 MAKMEMO_BEGIN (scm_list_2 (MAKMEMO_LET (scm_reverse (vals),
1144 MAKMEMO_BEGIN (sets)),
1145 memoize_sequence (CDDR (expr),
1146 new_env))));
1147 }
1148 }
1149
1150 static SCM
1151 scm_m_letstar (SCM expr, SCM env SCM_UNUSED)
1152 {
1153 SCM bindings;
1154
1155 const SCM cdr_expr = CDR (expr);
1156 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1157 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
1158
1159 bindings = CAR (cdr_expr);
1160 if (scm_is_null (bindings))
1161 return memoize_sequence (CDDR (expr), env);
1162 else
1163 {
1164 SCM rvariables;
1165 SCM variables;
1166 SCM inits;
1167 SCM ret, loc;
1168 transform_bindings (bindings, expr, &rvariables, &inits);
1169 variables = scm_reverse (rvariables);
1170 ret = scm_cons (SCM_UNDEFINED, SCM_UNSPECIFIED);
1171 loc = ret;
1172 for (; scm_is_pair (variables);
1173 variables = CDR (variables), inits = CDR (inits))
1174 { SCM x = MAKMEMO_LET (scm_list_1 (memoize (CAR (inits), env)),
1175 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
1176 SCM_SETCDR (loc, x);
1177 loc = scm_last_pair (SCM_MEMOIZED_ARGS (x));
1178 env = scm_cons (CAR (variables), env);
1179 }
1180 SCM_SETCDR (loc, memoize_sequence (CDDR (expr), env));
1181 return CDR (ret);
1182 }
1183 }
1184
1185 static SCM
1186 scm_m_or (SCM expr, SCM env SCM_UNUSED)
1187 {
1188 SCM tail = CDR (expr);
1189 SCM ret, loc;
1190 const long length = scm_ilength (tail);
1191
1192 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
1193
1194 ret = scm_cons (SCM_UNDEFINED, SCM_UNSPECIFIED);
1195 loc = ret;
1196 for (; scm_is_pair (tail); tail = CDR (tail))
1197 {
1198 SCM tmp = scm_gensym (scm_from_locale_string ("cond "));
1199 SCM x = MAKMEMO_IF (MAKMEMO_LEX_REF (0),
1200 MAKMEMO_LEX_REF (0),
1201 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
1202 SCM new_env = scm_cons (tmp, env);
1203 SCM_SETCDR (loc, MAKMEMO_LET (scm_list_1 (memoize (CAR (tail),
1204 env)),
1205 x));
1206 env = new_env;
1207 loc = scm_last_pair (SCM_MEMOIZED_ARGS (x));
1208 }
1209 SCM_SETCDR (loc, MAKMEMO_QUOTE (SCM_BOOL_F));
1210 return CDR (ret);
1211 }
1212
1213 static SCM
1214 scm_m_quote (SCM expr, SCM env SCM_UNUSED)
1215 {
1216 SCM quotee;
1217
1218 const SCM cdr_expr = CDR (expr);
1219 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1220 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 1, s_expression, expr);
1221 quotee = CAR (cdr_expr);
1222 return MAKMEMO_QUOTE (quotee);
1223 }
1224
1225 static SCM
1226 scm_m_set_x (SCM expr, SCM env)
1227 {
1228 SCM variable;
1229 SCM vmem;
1230
1231 const SCM cdr_expr = CDR (expr);
1232 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1233 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 2, s_expression, expr);
1234 variable = CAR (cdr_expr);
1235 vmem = memoize (variable, env);
1236
1237 switch (SCM_MEMOIZED_TAG (vmem))
1238 {
1239 case SCM_M_LEXICAL_REF:
1240 return MAKMEMO_LEX_SET (SCM_I_INUM (SCM_MEMOIZED_ARGS (vmem)),
1241 memoize (CADDR (expr), env));
1242 case SCM_M_TOPLEVEL_REF:
1243 return MAKMEMO_TOP_SET (variable,
1244 memoize (CADDR (expr), env));
1245 case SCM_M_MODULE_REF:
1246 return MAKMEMO_MOD_SET (memoize (CADDR (expr), env),
1247 CAR (SCM_MEMOIZED_ARGS (vmem)),
1248 CADR (SCM_MEMOIZED_ARGS (vmem)),
1249 CDDR (SCM_MEMOIZED_ARGS (vmem)));
1250 default:
1251 syntax_error (s_bad_variable, variable, expr);
1252 }
1253 }
1254
1255
1256 \f
1257
1258 SCM_DEFINE (scm_memoize_expression, "memoize-expression", 1, 0, 0,
1259 (SCM exp),
1260 "Memoize the expression @var{exp}.")
1261 #define FUNC_NAME s_scm_memoize_expression
1262 {
1263 return memoize (exp, scm_current_module ());
1264 }
1265 #undef FUNC_NAME
1266
1267
1268 \f
1269
1270 #define SCM_MAKE_MEMOIZER(STR, MEMOIZER, N) \
1271 (scm_cell (scm_tc16_memoizer, \
1272 (scm_t_bits)(scm_c_make_gsubr (STR, N, 0, 0, MEMOIZER))))
1273 #define SCM_DEFINE_MEMOIZER(STR, MEMOIZER, N) \
1274 SCM_SNARF_INIT(scm_c_define (STR, SCM_MAKE_MEMOIZER (STR, MEMOIZER, N)))
1275
1276 static SCM m_apply (SCM proc, SCM args);
1277 static SCM m_call_cc (SCM proc);
1278 static SCM m_call_values (SCM prod, SCM cons);
1279 static SCM m_dynamic_wind (SCM pre, SCM exp, SCM post);
1280 static SCM m_prompt (SCM tag, SCM exp, SCM handler);
1281
1282 SCM_DEFINE_MEMOIZER ("@apply", m_apply, 2);
1283 SCM_DEFINE_MEMOIZER ("@call-with-current-continuation", m_call_cc, 1);
1284 SCM_DEFINE_MEMOIZER ("@call-with-values", m_call_values, 2);
1285 SCM_DEFINE_MEMOIZER ("@dynamic-wind", m_dynamic_wind, 3);
1286 SCM_DEFINE_MEMOIZER ("@prompt", m_prompt, 3);
1287
1288
1289 \f
1290
1291 static SCM m_apply (SCM proc, SCM args)
1292 #define FUNC_NAME "@apply"
1293 {
1294 SCM_VALIDATE_MEMOIZED (1, proc);
1295 SCM_VALIDATE_MEMOIZED (2, args);
1296 return MAKMEMO_APPLY (proc, args);
1297 }
1298 #undef FUNC_NAME
1299
1300 static SCM m_call_cc (SCM proc)
1301 #define FUNC_NAME "@call-with-current-continuation"
1302 {
1303 SCM_VALIDATE_MEMOIZED (1, proc);
1304 return MAKMEMO_CONT (proc);
1305 }
1306 #undef FUNC_NAME
1307
1308 static SCM m_call_values (SCM prod, SCM cons)
1309 #define FUNC_NAME "@call-with-values"
1310 {
1311 SCM_VALIDATE_MEMOIZED (1, prod);
1312 SCM_VALIDATE_MEMOIZED (2, cons);
1313 return MAKMEMO_CALL_WITH_VALUES (prod, cons);
1314 }
1315 #undef FUNC_NAME
1316
1317 static SCM m_dynamic_wind (SCM in, SCM expr, SCM out)
1318 #define FUNC_NAME "memoize-dynwind"
1319 {
1320 SCM_VALIDATE_MEMOIZED (1, in);
1321 SCM_VALIDATE_MEMOIZED (2, expr);
1322 SCM_VALIDATE_MEMOIZED (3, out);
1323 return MAKMEMO_DYNWIND (in, expr, out);
1324 }
1325 #undef FUNC_NAME
1326
1327 static SCM m_prompt (SCM tag, SCM exp, SCM handler)
1328 #define FUNC_NAME "@prompt"
1329 {
1330 SCM_VALIDATE_MEMOIZED (1, tag);
1331 SCM_VALIDATE_MEMOIZED (2, exp);
1332 SCM_VALIDATE_MEMOIZED (3, handler);
1333 return MAKMEMO_PROMPT (tag, exp, handler);
1334 }
1335 #undef FUNC_NAME
1336
1337 SCM_DEFINE (scm_memoizer_p, "memoizer?", 1, 0, 0,
1338 (SCM x), "")
1339 {
1340 return scm_from_bool (SCM_MEMOIZER_P (x));
1341 }
1342
1343 SCM_DEFINE (scm_memoizer, "memoizer", 1, 0, 0,
1344 (SCM memoizer), "")
1345 {
1346 SCM_ASSERT (SCM_MEMOIZER_P (memoizer), memoizer, 1, "memoizer?");
1347 return SCM_MEMOIZER (memoizer);
1348 }
1349
1350
1351 \f
1352
1353 #define SCM_VALIDATE_MEMOIZED_LIST(n, exps) \
1354 { \
1355 SCM walk; \
1356 for (walk = exps; scm_is_pair (walk); walk = scm_cdr (walk)) \
1357 SCM_ASSERT (SCM_MEMOIZED_P (scm_car (walk)), exps, n, FUNC_NAME); \
1358 SCM_ASSERT (scm_is_null (walk), exps, n, FUNC_NAME); \
1359 }
1360
1361 SCM_DEFINE (scm_memoize_begin, "memoize-begin", 1, 0, 0,
1362 (SCM exps), "")
1363 #define FUNC_NAME s_scm_memoize_begin
1364 {
1365 SCM_VALIDATE_MEMOIZED_LIST (1, exps);
1366 return MAKMEMO_BEGIN (exps);
1367 }
1368 #undef FUNC_NAME
1369
1370 SCM_DEFINE (scm_memoize_if, "memoize-if", 3, 0, 0,
1371 (SCM test, SCM then, SCM else_), "")
1372 #define FUNC_NAME s_scm_memoize_if
1373 {
1374 SCM_VALIDATE_MEMOIZED (1, test);
1375 SCM_VALIDATE_MEMOIZED (2, then);
1376 SCM_VALIDATE_MEMOIZED (3, else_);
1377 return MAKMEMO_IF (test, then, else_);
1378 }
1379 #undef FUNC_NAME
1380
1381 SCM_DEFINE (scm_memoize_lambda, "memoize-lambda", 3, 4, 0,
1382 (SCM body, SCM nreq, SCM rest, SCM nopt, SCM kw, SCM inits, SCM alt), "")
1383 #define FUNC_NAME s_scm_memoize_lambda
1384 {
1385 SCM_VALIDATE_MEMOIZED (1, body);
1386 if (SCM_UNBNDP (nopt))
1387 {
1388 if (scm_is_true (rest))
1389 return MAKMEMO_LAMBDA (body, FIXED_ARITY (scm_to_uint16 (nreq)));
1390 else
1391 MAKMEMO_LAMBDA (body, REST_ARITY (scm_to_uint16 (nreq), rest));
1392 }
1393 if (SCM_UNBNDP (kw))
1394 kw = SCM_BOOL_F;
1395 if (SCM_UNBNDP (inits))
1396 inits = SCM_EOL;
1397 if (SCM_UNBNDP (alt))
1398 alt = SCM_BOOL_F;
1399 else
1400 SCM_VALIDATE_MEMOIZED (7, alt);
1401 return MAKMEMO_LAMBDA (body,
1402 FULL_ARITY (scm_to_uint16 (nreq), rest,
1403 scm_to_uint16 (nopt), kw, inits, alt));
1404
1405 }
1406 #undef FUNC_NAME
1407
1408 SCM_DEFINE (scm_memoize_let, "memoize-let", 2, 0, 0,
1409 (SCM inits, SCM body), "")
1410 #define FUNC_NAME s_scm_memoize_let
1411 {
1412 SCM_VALIDATE_MEMOIZED_LIST (1, inits);
1413 SCM_VALIDATE_MEMOIZED (2, body);
1414 return MAKMEMO_LET (inits, body);
1415 }
1416 #undef FUNC_NAME
1417
1418 SCM_DEFINE (scm_memoize_quote, "memoize-quote", 1, 0, 0,
1419 (SCM exp), "")
1420 #define FUNC_NAME s_scm_memoize_quote
1421 {
1422 return MAKMEMO_QUOTE (exp);
1423 }
1424 #undef FUNC_NAME
1425
1426 SCM_DEFINE (scm_memoize_define, "memoize-define", 2, 0, 0,
1427 (SCM var, SCM val), "")
1428 #define FUNC_NAME s_scm_memoize_define
1429 {
1430 SCM_VALIDATE_SYMBOL (1, var);
1431 SCM_VALIDATE_MEMOIZED (2, val);
1432 return MAKMEMO_DEFINE (var, val);
1433 }
1434 #undef FUNC_NAME
1435
1436 SCM_DEFINE (scm_memoize_with_fluids, "memoize-with-fluids", 3, 0, 0,
1437 (SCM fluids, SCM vals, SCM expr), "")
1438 #define FUNC_NAME s_scm_memoize_with_fluids
1439 {
1440 SCM_VALIDATE_MEMOIZED_LIST (1, fluids);
1441 SCM_VALIDATE_MEMOIZED_LIST (2, vals);
1442 SCM_ASSERT (scm_ilength (fluids) == scm_ilength (vals), vals, 2, FUNC_NAME);
1443 SCM_VALIDATE_MEMOIZED (3, expr);
1444 return MAKMEMO_WITH_FLUIDS (fluids, vals, expr);
1445 }
1446 #undef FUNC_NAME
1447
1448 SCM_DEFINE (scm_memoize_call, "memoize-call", 3, 0, 0,
1449 (SCM proc, SCM nargs, SCM args), "")
1450 #define FUNC_NAME s_scm_memoize_call
1451 {
1452 SCM_VALIDATE_MEMOIZED (1, proc);
1453 SCM_VALIDATE_MEMOIZED_LIST (3, args);
1454 return MAKMEMO_CALL (proc, scm_to_uint16 (nargs), args);
1455 }
1456 #undef FUNC_NAME
1457
1458 SCM_DEFINE (scm_memoize_lexical_ref, "memoize-lexical-ref", 1, 0, 0,
1459 (SCM n), "")
1460 #define FUNC_NAME s_scm_memoize_lexical_ref
1461 {
1462 return MAKMEMO_LEX_REF (scm_to_uint16 (n));
1463 }
1464 #undef FUNC_NAME
1465
1466 SCM_DEFINE (scm_memoize_lexical_set, "memoize-lexical-set!", 2, 0, 0,
1467 (SCM n, SCM val), "")
1468 #define FUNC_NAME s_scm_memoize_lexical_set
1469 {
1470 SCM_VALIDATE_MEMOIZED (1, val);
1471 return MAKMEMO_LEX_SET (n, val);
1472 }
1473 #undef FUNC_NAME
1474
1475 SCM_DEFINE (scm_memoize_toplevel_ref, "memoize-toplevel-ref", 1, 0, 0,
1476 (SCM var), "")
1477 #define FUNC_NAME s_scm_memoize_toplevel_ref
1478 {
1479 SCM_VALIDATE_SYMBOL (1, var);
1480 return MAKMEMO_TOP_REF (var);
1481 }
1482 #undef FUNC_NAME
1483
1484 SCM_DEFINE (scm_memoize_toplevel_set, "memoize-toplevel-set!", 2, 0, 0,
1485 (SCM var, SCM val), "")
1486 #define FUNC_NAME s_scm_memoize_toplevel_set
1487 {
1488 SCM_VALIDATE_SYMBOL (1, var);
1489 SCM_VALIDATE_MEMOIZED (2, val);
1490 return MAKMEMO_TOP_SET (var, val);
1491 }
1492 #undef FUNC_NAME
1493
1494 SCM_DEFINE (scm_memoize_module_ref, "memoize-module-ref", 3, 0, 0,
1495 (SCM mod, SCM var, SCM public), "")
1496 #define FUNC_NAME s_scm_memoize_module_ref
1497 {
1498 SCM_VALIDATE_SYMBOL (2, var);
1499 SCM_VALIDATE_BOOL (3, public);
1500 return MAKMEMO_MOD_REF (mod, var, public);
1501 }
1502 #undef FUNC_NAME
1503
1504 SCM_DEFINE (scm_memoize_module_set, "memoize-module-set!", 4, 0, 0,
1505 (SCM val, SCM mod, SCM var, SCM public), "")
1506 #define FUNC_NAME s_scm_memoize_module_set
1507 {
1508 SCM_VALIDATE_MEMOIZED (1, val);
1509 SCM_VALIDATE_SYMBOL (3, var);
1510 SCM_VALIDATE_BOOL (4, public);
1511 return MAKMEMO_MOD_SET (val, mod, var, public);
1512 }
1513 #undef FUNC_NAME
1514
1515
1516 \f
1517
1518 SCM_SYMBOL (sym_placeholder, "_");
1519
1520 static SCM unmemoize (SCM expr);
1521
1522 static SCM
1523 unmemoize_exprs (SCM exprs)
1524 {
1525 SCM ret, tail;
1526 if (scm_is_null (exprs))
1527 return SCM_EOL;
1528 ret = scm_list_1 (unmemoize (CAR (exprs)));
1529 tail = ret;
1530 for (exprs = CDR (exprs); !scm_is_null (exprs); exprs = CDR (exprs))
1531 {
1532 SCM_SETCDR (tail, scm_list_1 (unmemoize (CAR (exprs))));
1533 tail = CDR (tail);
1534 }
1535 return ret;
1536 }
1537
1538 static SCM
1539 unmemoize_bindings (SCM inits)
1540 {
1541 SCM ret, tail;
1542 if (scm_is_null (inits))
1543 return SCM_EOL;
1544 ret = scm_list_1 (scm_list_2 (sym_placeholder, unmemoize (CAR (inits))));
1545 tail = ret;
1546 for (inits = CDR (inits); !scm_is_null (inits); inits = CDR (inits))
1547 {
1548 SCM_SETCDR (tail, scm_list_1 (scm_list_2 (sym_placeholder,
1549 unmemoize (CAR (inits)))));
1550 tail = CDR (tail);
1551 }
1552 return ret;
1553 }
1554
1555 static SCM
1556 unmemoize_lexical (SCM n)
1557 {
1558 char buf[16];
1559 buf[15] = 0;
1560 snprintf (buf, 15, "<%u>", scm_to_uint32 (n));
1561 return scm_from_locale_symbol (buf);
1562 }
1563
1564 static SCM
1565 unmemoize (const SCM expr)
1566 {
1567 SCM args;
1568
1569 if (!SCM_MEMOIZED_P (expr))
1570 abort ();
1571
1572 args = SCM_MEMOIZED_ARGS (expr);
1573 switch (SCM_MEMOIZED_TAG (expr))
1574 {
1575 case SCM_M_APPLY:
1576 return scm_cons (scm_sym_atapply, unmemoize_exprs (args));
1577 case SCM_M_BEGIN:
1578 return scm_cons (scm_sym_begin, unmemoize_exprs (args));
1579 case SCM_M_CALL:
1580 return scm_cons (unmemoize (CAR (args)), unmemoize_exprs (CDDR (args)));
1581 case SCM_M_CONT:
1582 return scm_list_2 (scm_sym_atcall_cc, unmemoize (args));
1583 case SCM_M_CALL_WITH_VALUES:
1584 return scm_list_3 (scm_sym_at_call_with_values,
1585 unmemoize (CAR (args)), unmemoize (CDR (args)));
1586 case SCM_M_DEFINE:
1587 return scm_list_3 (scm_sym_define, CAR (args), unmemoize (CDR (args)));
1588 case SCM_M_DYNWIND:
1589 return scm_list_4 (scm_sym_at_dynamic_wind,
1590 unmemoize (CAR (args)),
1591 unmemoize (CADR (args)),
1592 unmemoize (CDDR (args)));
1593 case SCM_M_WITH_FLUIDS:
1594 {
1595 SCM binds = SCM_EOL, fluids, vals;
1596 for (fluids = CAR (args), vals = CADR (args); scm_is_pair (fluids);
1597 fluids = CDR (fluids), vals = CDR (vals))
1598 binds = scm_cons (scm_list_2 (unmemoize (CAR (fluids)),
1599 unmemoize (CAR (vals))),
1600 binds);
1601 return scm_list_3 (scm_sym_with_fluids,
1602 scm_reverse_x (binds, SCM_UNDEFINED),
1603 unmemoize (CDDR (args)));
1604 }
1605 case SCM_M_IF:
1606 return scm_list_4 (scm_sym_if, unmemoize (scm_car (args)),
1607 unmemoize (scm_cadr (args)), unmemoize (scm_cddr (args)));
1608 case SCM_M_LAMBDA:
1609 if (scm_is_null (CDDR (args)))
1610 return scm_list_3 (scm_sym_lambda,
1611 scm_make_list (CADR (args), sym_placeholder),
1612 unmemoize (CAR (args)));
1613 else if (scm_is_null (CDDDR (args)))
1614 {
1615 SCM formals = scm_make_list (CADR (args), sym_placeholder);
1616 return scm_list_3 (scm_sym_lambda,
1617 scm_is_true (CADDR (args))
1618 ? scm_cons_star (sym_placeholder, formals)
1619 : formals,
1620 unmemoize (CAR (args)));
1621 }
1622 else
1623 {
1624 SCM body = CAR (args), spec = CDR (args), alt, tail;
1625
1626 alt = CADDR (CDDDR (spec));
1627 if (scm_is_true (alt))
1628 tail = CDR (unmemoize (alt));
1629 else
1630 tail = SCM_EOL;
1631
1632 return scm_cons
1633 (sym_case_lambda_star,
1634 scm_cons (scm_list_2 (scm_list_5 (CAR (spec),
1635 CADR (spec),
1636 CADDR (spec),
1637 CADDDR (spec),
1638 unmemoize_exprs (CADR (CDDDR (spec)))),
1639 unmemoize (body)),
1640 tail));
1641 }
1642 case SCM_M_LET:
1643 return scm_list_3 (scm_sym_let,
1644 unmemoize_bindings (CAR (args)),
1645 unmemoize (CDR (args)));
1646 case SCM_M_QUOTE:
1647 return scm_list_2 (scm_sym_quote, args);
1648 case SCM_M_LEXICAL_REF:
1649 return unmemoize_lexical (args);
1650 case SCM_M_LEXICAL_SET:
1651 return scm_list_3 (scm_sym_set_x, unmemoize_lexical (CAR (args)),
1652 unmemoize (CDR (args)));
1653 case SCM_M_TOPLEVEL_REF:
1654 return args;
1655 case SCM_M_TOPLEVEL_SET:
1656 return scm_list_3 (scm_sym_set_x, CAR (args), unmemoize (CDR (args)));
1657 case SCM_M_MODULE_REF:
1658 return SCM_VARIABLEP (args) ? args
1659 : scm_list_3 (scm_is_true (CDDR (args)) ? scm_sym_at : scm_sym_atat,
1660 scm_i_finite_list_copy (CAR (args)),
1661 CADR (args));
1662 case SCM_M_MODULE_SET:
1663 return scm_list_3 (scm_sym_set_x,
1664 SCM_VARIABLEP (CDR (args)) ? CDR (args)
1665 : scm_list_3 (scm_is_true (CDDDR (args))
1666 ? scm_sym_at : scm_sym_atat,
1667 scm_i_finite_list_copy (CADR (args)),
1668 CADDR (args)),
1669 unmemoize (CAR (args)));
1670 case SCM_M_PROMPT:
1671 return scm_list_4 (scm_sym_at_prompt,
1672 unmemoize (CAR (args)),
1673 unmemoize (CADR (args)),
1674 unmemoize (CDDR (args)));
1675 default:
1676 abort ();
1677 }
1678 }
1679
1680
1681 \f
1682
1683 SCM_DEFINE (scm_memoized_p, "memoized?", 1, 0, 0,
1684 (SCM obj),
1685 "Return @code{#t} if @var{obj} is memoized.")
1686 #define FUNC_NAME s_scm_memoized_p
1687 {
1688 return scm_from_bool (SCM_MEMOIZED_P (obj));
1689 }
1690 #undef FUNC_NAME
1691
1692 SCM_DEFINE (scm_unmemoize_expression, "unmemoize-expression", 1, 0, 0,
1693 (SCM m),
1694 "Unmemoize the memoized expression @var{m}.")
1695 #define FUNC_NAME s_scm_unmemoize_expression
1696 {
1697 SCM_VALIDATE_MEMOIZED (1, m);
1698 return unmemoize (m);
1699 }
1700 #undef FUNC_NAME
1701
1702 SCM_DEFINE (scm_memoized_expression_typecode, "memoized-expression-typecode", 1, 0, 0,
1703 (SCM m),
1704 "Return the typecode from the memoized expression @var{m}.")
1705 #define FUNC_NAME s_scm_memoized_expression_typecode
1706 {
1707 SCM_VALIDATE_MEMOIZED (1, m);
1708
1709 /* The tag is a 16-bit integer so it fits in an inum. */
1710 return SCM_I_MAKINUM (SCM_MEMOIZED_TAG (m));
1711 }
1712 #undef FUNC_NAME
1713
1714 SCM_DEFINE (scm_memoized_expression_data, "memoized-expression-data", 1, 0, 0,
1715 (SCM m),
1716 "Return the data from the memoized expression @var{m}.")
1717 #define FUNC_NAME s_scm_memoized_expression_data
1718 {
1719 SCM_VALIDATE_MEMOIZED (1, m);
1720 return SCM_MEMOIZED_ARGS (m);
1721 }
1722 #undef FUNC_NAME
1723
1724 SCM_DEFINE (scm_memoized_typecode, "memoized-typecode", 1, 0, 0,
1725 (SCM sym),
1726 "Return the memoized typecode corresponding to the symbol @var{sym}.")
1727 #define FUNC_NAME s_scm_memoized_typecode
1728 {
1729 int i;
1730
1731 SCM_VALIDATE_SYMBOL (1, sym);
1732
1733 for (i = 0; i < sizeof(memoized_tags)/sizeof(const char*); i++)
1734 if (strcmp (scm_i_symbol_chars (sym), memoized_tags[i]) == 0)
1735 return scm_from_int32 (i);
1736
1737 return SCM_BOOL_F;
1738 }
1739 #undef FUNC_NAME
1740
1741 SCM_SYMBOL (scm_unbound_variable_key, "unbound-variable");
1742 static void error_unbound_variable (SCM symbol) SCM_NORETURN;
1743 static void error_unbound_variable (SCM symbol)
1744 {
1745 scm_error (scm_unbound_variable_key, NULL, "Unbound variable: ~S",
1746 scm_list_1 (symbol), SCM_BOOL_F);
1747 }
1748
1749 SCM_DEFINE (scm_memoize_variable_access_x, "memoize-variable-access!", 2, 0, 0,
1750 (SCM m, SCM mod),
1751 "Look up and cache the variable that @var{m} will access, returning the variable.")
1752 #define FUNC_NAME s_scm_memoize_variable_access_x
1753 {
1754 SCM mx;
1755 SCM_VALIDATE_MEMOIZED (1, m);
1756 mx = SCM_MEMOIZED_ARGS (m);
1757 switch (SCM_MEMOIZED_TAG (m))
1758 {
1759 case SCM_M_TOPLEVEL_REF:
1760 if (SCM_VARIABLEP (mx))
1761 return mx;
1762 else
1763 {
1764 SCM var = scm_module_variable (mod, mx);
1765 if (scm_is_false (var) || scm_is_false (scm_variable_bound_p (var)))
1766 error_unbound_variable (mx);
1767 SCM_SET_SMOB_OBJECT (m, var);
1768 return var;
1769 }
1770
1771 case SCM_M_TOPLEVEL_SET:
1772 {
1773 SCM var = CAR (mx);
1774 if (SCM_VARIABLEP (var))
1775 return var;
1776 else
1777 {
1778 var = scm_module_variable (mod, var);
1779 if (scm_is_false (var))
1780 error_unbound_variable (CAR (mx));
1781 SCM_SETCAR (mx, var);
1782 return var;
1783 }
1784 }
1785
1786 case SCM_M_MODULE_REF:
1787 if (SCM_VARIABLEP (mx))
1788 return mx;
1789 else
1790 {
1791 SCM var;
1792 mod = scm_resolve_module (CAR (mx));
1793 if (scm_is_true (CDDR (mx)))
1794 mod = scm_module_public_interface (mod);
1795 var = scm_module_lookup (mod, CADR (mx));
1796 if (scm_is_false (scm_variable_bound_p (var)))
1797 error_unbound_variable (CADR (mx));
1798 SCM_SET_SMOB_OBJECT (m, var);
1799 return var;
1800 }
1801
1802 case SCM_M_MODULE_SET:
1803 /* FIXME: not quite threadsafe */
1804 if (SCM_VARIABLEP (CDR (mx)))
1805 return CDR (mx);
1806 else
1807 {
1808 SCM var;
1809 mod = scm_resolve_module (CADR (mx));
1810 if (scm_is_true (CDDDR (mx)))
1811 mod = scm_module_public_interface (mod);
1812 var = scm_module_lookup (mod, CADDR (mx));
1813 SCM_SETCDR (mx, var);
1814 return var;
1815 }
1816
1817 default:
1818 scm_wrong_type_arg (FUNC_NAME, 1, m);
1819 return SCM_BOOL_F;
1820 }
1821 }
1822 #undef FUNC_NAME
1823
1824
1825 \f
1826
1827 void
1828 scm_init_memoize ()
1829 {
1830 scm_tc16_memoized = scm_make_smob_type ("%memoized", 0);
1831 scm_set_smob_mark (scm_tc16_memoized, scm_markcdr);
1832 scm_set_smob_print (scm_tc16_memoized, scm_print_memoized);
1833
1834 scm_tc16_memoizer = scm_make_smob_type ("memoizer", 0);
1835
1836 #include "libguile/memoize.x"
1837
1838 scm_c_define ("macroexpand",
1839 scm_variable_ref (scm_c_lookup ("memoize-expression")));
1840 }
1841
1842 /*
1843 Local Variables:
1844 c-file-style: "gnu"
1845 End:
1846 */