scm_badargsp is deprecated
[bpt/guile.git] / libguile / memoize.c
CommitLineData
bab98046 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
b7742c6b
AW
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
b7742c6b 26#include "libguile/__scm.h"
b7742c6b
AW
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
b7742c6b
AW
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)
b7ecadca 53#define CADDDR(x) SCM_CADDDR(x)
b7742c6b
AW
54
55
56static const char s_bad_expression[] = "Bad expression";
57static const char s_expression[] = "Missing or extra expression in";
58static const char s_missing_expression[] = "Missing expression in";
59static const char s_extra_expression[] = "Extra expression in";
60static const char s_empty_combination[] = "Illegal empty combination";
61static const char s_missing_body_expression[] = "Missing body expression in";
62static const char s_mixed_body_forms[] = "Mixed definitions and expressions in";
63static const char s_bad_define[] = "Bad define placement";
64static const char s_missing_clauses[] = "Missing clauses";
65static const char s_misplaced_else_clause[] = "Misplaced else clause";
66static const char s_bad_case_clause[] = "Bad case clause";
67static const char s_bad_case_labels[] = "Bad case labels";
68static const char s_duplicate_case_label[] = "Duplicate case label";
69static const char s_bad_cond_clause[] = "Bad cond clause";
70static const char s_missing_recipient[] = "Missing recipient in";
71static const char s_bad_variable[] = "Bad variable";
72static const char s_bad_bindings[] = "Bad bindings";
73static const char s_bad_binding[] = "Bad binding";
74static const char s_duplicate_binding[] = "Duplicate binding";
75static const char s_bad_exit_clause[] = "Bad exit clause";
76static const char s_bad_formals[] = "Bad formals";
77static const char s_bad_formal[] = "Bad formal";
78static const char s_duplicate_formal[] = "Duplicate formal";
79static const char s_splicing[] = "Non-list result for unquote-splicing";
80static 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
92SCM_SYMBOL (syntax_error_key, "syntax-error");
93
94/* The prototype is needed to indicate that the function does not return. */
95static void
96syntax_error (const char* const, const SCM, const SCM) SCM_NORETURN;
97
98static void
99syntax_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
174scm_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 MAKMEMO_LAMBDA(nreq, rest, body) \
183 MAKMEMO (SCM_M_LAMBDA, scm_cons (SCM_I_MAKINUM (nreq), scm_cons (rest, body)))
184#define MAKMEMO_LET(inits, body) \
185 MAKMEMO (SCM_M_LET, scm_cons (inits, body))
186#define MAKMEMO_QUOTE(exp) \
187 MAKMEMO (SCM_M_QUOTE, exp)
188#define MAKMEMO_DEFINE(var, val) \
189 MAKMEMO (SCM_M_DEFINE, scm_cons (var, val))
d69531e2
AW
190#define MAKMEMO_DYNWIND(in, expr, out) \
191 MAKMEMO (SCM_M_DYNWIND, scm_cons (in, scm_cons (expr, out)))
bb0229b5
AW
192#define MAKMEMO_WITH_FLUIDS(fluids, vals, expr) \
193 MAKMEMO (SCM_M_WITH_FLUIDS, scm_cons (fluids, scm_cons (vals, expr)))
2cd72a84
AW
194#define MAKMEMO_APPLY(proc, args)\
195 MAKMEMO (SCM_M_APPLY, scm_list_2 (proc, args))
b7742c6b
AW
196#define MAKMEMO_CONT(proc) \
197 MAKMEMO (SCM_M_CONT, proc)
198#define MAKMEMO_CALL_WITH_VALUES(prod, cons) \
199 MAKMEMO (SCM_M_CALL_WITH_VALUES, scm_cons (prod, cons))
9331f91c
AW
200#define MAKMEMO_CALL(proc, nargs, args) \
201 MAKMEMO (SCM_M_CALL, scm_cons (proc, scm_cons (SCM_I_MAKINUM (nargs), args)))
b7742c6b
AW
202#define MAKMEMO_LEX_REF(n) \
203 MAKMEMO (SCM_M_LEXICAL_REF, SCM_I_MAKINUM (n))
204#define MAKMEMO_LEX_SET(n, val) \
205 MAKMEMO (SCM_M_LEXICAL_SET, scm_cons (SCM_I_MAKINUM (n), val))
206#define MAKMEMO_TOP_REF(var) \
207 MAKMEMO (SCM_M_TOPLEVEL_REF, var)
208#define MAKMEMO_TOP_SET(var, val) \
209 MAKMEMO (SCM_M_TOPLEVEL_SET, scm_cons (var, val))
210#define MAKMEMO_MOD_REF(mod, var, public) \
211 MAKMEMO (SCM_M_MODULE_REF, scm_cons (mod, scm_cons (var, public)))
212#define MAKMEMO_MOD_SET(val, mod, var, public) \
213 MAKMEMO (SCM_M_MODULE_SET, scm_cons (val, scm_cons (mod, scm_cons (var, public))))
747022e4
AW
214#define MAKMEMO_PROMPT(tag, exp, handler) \
215 MAKMEMO (SCM_M_PROMPT, scm_cons (tag, scm_cons (exp, handler)))
b7742c6b 216
2cd72a84
AW
217
218/* Primitives for the evaluator */
219scm_t_bits scm_tc16_memoizer;
220#define SCM_MEMOIZER_P(x) (SCM_SMOB_PREDICATE (scm_tc16_memoizer, (x)))
221#define SCM_MEMOIZER(M) (SCM_SMOB_OBJECT_1 (M))
222
b7742c6b
AW
223\f
224
225/* This table must agree with the list of M_ constants in memoize.h */
226static const char *const memoized_tags[] =
227{
228 "begin",
229 "if",
230 "lambda",
231 "let",
232 "quote",
233 "define",
d69531e2 234 "dynwind",
bb0229b5 235 "with-fluids",
b7742c6b 236 "apply",
3149a5b6 237 "call/cc",
b7742c6b
AW
238 "call-with-values",
239 "call",
240 "lexical-ref",
241 "lexical-set!",
242 "toplevel-ref",
243 "toplevel-set!",
244 "module-ref",
3149a5b6 245 "module-set!",
747022e4 246 "prompt",
b7742c6b
AW
247};
248
249static int
250scm_print_memoized (SCM memoized, SCM port, scm_print_state *pstate)
251{
252 scm_puts ("#<memoized ", port);
253 scm_write (scm_unmemoize_expression (memoized), port);
254 scm_puts (">", port);
255 return 1;
256}
257
258static SCM scm_m_at (SCM xorig, SCM env);
259static SCM scm_m_atat (SCM xorig, SCM env);
260static SCM scm_m_and (SCM xorig, SCM env);
b7742c6b 261static SCM scm_m_begin (SCM xorig, SCM env);
b7742c6b
AW
262static SCM scm_m_cond (SCM xorig, SCM env);
263static SCM scm_m_define (SCM x, SCM env);
bb0229b5 264static SCM scm_m_with_fluids (SCM xorig, SCM env);
b7742c6b
AW
265static SCM scm_m_eval_when (SCM xorig, SCM env);
266static SCM scm_m_if (SCM xorig, SCM env);
267static SCM scm_m_lambda (SCM xorig, SCM env);
268static SCM scm_m_let (SCM xorig, SCM env);
269static SCM scm_m_letrec (SCM xorig, SCM env);
270static SCM scm_m_letstar (SCM xorig, SCM env);
271static SCM scm_m_or (SCM xorig, SCM env);
272static SCM scm_m_quote (SCM xorig, SCM env);
273static SCM scm_m_set_x (SCM xorig, SCM env);
274
b7742c6b
AW
275\f
276
277
2cd72a84
AW
278static SCM
279memoize_env_ref_macro (SCM env, SCM x)
b7742c6b
AW
280{
281 SCM var;
282 for (; scm_is_pair (env); env = CDR (env))
283 if (scm_is_eq (x, CAR (env)))
2cd72a84 284 return SCM_BOOL_F; /* lexical */
b7742c6b
AW
285
286 var = scm_module_variable (env, x);
287 if (scm_is_true (var) && scm_is_true (scm_variable_bound_p (var))
2cd72a84
AW
288 && (scm_is_true (scm_macro_p (scm_variable_ref (var)))
289 || SCM_MEMOIZER_P (scm_variable_ref (var))))
290 return scm_variable_ref (var);
b7742c6b 291 else
2cd72a84 292 return SCM_BOOL_F; /* anything else */
b7742c6b
AW
293}
294
295static int
296memoize_env_var_is_free (SCM env, SCM x)
297{
298 for (; scm_is_pair (env); env = CDR (env))
299 if (scm_is_eq (x, CAR (env)))
300 return 0; /* bound */
301 return 1; /* free */
302}
303
304static int
305memoize_env_lexical_index (SCM env, SCM x)
306{
307 int i = 0;
308 for (; scm_is_pair (env); env = CDR (env), i++)
309 if (scm_is_eq (x, CAR (env)))
310 return i; /* bound */
311 return -1; /* free */
312}
313
314static SCM
315memoize_env_extend (SCM env, SCM vars)
316{
317 return scm_append (scm_list_2 (vars, env));
318}
319
320static SCM
321memoize (SCM exp, SCM env)
322{
323 if (scm_is_pair (exp))
324 {
2cd72a84
AW
325 SCM car;
326 scm_t_macro_primitive trans = NULL;
327 SCM macro = SCM_BOOL_F, memoizer = SCM_BOOL_F;
b7742c6b 328
2cd72a84
AW
329 car = CAR (exp);
330 if (scm_is_symbol (car))
331 macro = memoize_env_ref_macro (env, car);
b7742c6b 332
2cd72a84
AW
333 if (scm_is_true (scm_macro_p (macro)))
334 trans = scm_i_macro_primitive (macro);
335 else if (SCM_MEMOIZER_P (macro))
336 memoizer = SCM_MEMOIZER (macro);
337
b7742c6b
AW
338 if (trans)
339 return trans (exp, env);
340 else
341 {
342 SCM args = SCM_EOL;
9331f91c 343 int nargs = 0;
2cd72a84
AW
344 SCM proc = CAR (exp);
345
9331f91c 346 for (exp = CDR (exp); scm_is_pair (exp); exp = CDR (exp), nargs++)
b7742c6b
AW
347 args = scm_cons (memoize (CAR (exp), env), args);
348 if (scm_is_null (exp))
2cd72a84
AW
349 {
350 if (scm_is_true (memoizer))
351 return scm_apply (memoizer, scm_reverse_x (args, SCM_UNDEFINED),
352 SCM_EOL);
353 else
354 return MAKMEMO_CALL (memoize (proc, env),
355 nargs,
356 scm_reverse_x (args, SCM_UNDEFINED));
357 }
358
b7742c6b
AW
359 else
360 syntax_error ("expected a proper list", exp, SCM_UNDEFINED);
361 }
362 }
363 else if (scm_is_symbol (exp))
364 {
365 int i = memoize_env_lexical_index (env, exp);
366 if (i < 0)
367 return MAKMEMO_TOP_REF (exp);
368 else
369 return MAKMEMO_LEX_REF (i);
370 }
371 else
372 return MAKMEMO_QUOTE (exp);
373}
374
375static SCM
376memoize_exprs (SCM forms, const SCM env)
377{
378 SCM ret = SCM_EOL;
379
380 for (; !scm_is_null (forms); forms = CDR (forms))
381 ret = scm_cons (memoize (CAR (forms), env), ret);
382 return scm_reverse_x (ret, SCM_UNDEFINED);
383}
384
385static SCM
386memoize_sequence (const SCM forms, const SCM env)
387{
388 ASSERT_SYNTAX (scm_ilength (forms) >= 1, s_bad_expression,
389 scm_cons (scm_sym_begin, forms));
b5e9f3f9
AW
390 if (scm_is_null (CDR (forms)))
391 return memoize (CAR (forms), env);
392 else
393 return MAKMEMO_BEGIN (memoize_exprs (forms, env));
b7742c6b
AW
394}
395
396
397\f
398/* Memoization. */
399
bab98046
AW
400#define SCM_SYNTAX(RANAME, STR, CFN) \
401SCM_SNARF_HERE(static const char RANAME[]=STR)\
e809758a 402SCM_SNARF_INIT(scm_c_define (RANAME, scm_i_make_primitive_macro (RANAME, CFN)))
bab98046 403
2cd72a84
AW
404
405/* True primitive syntax */
bab98046
AW
406SCM_SYNTAX (s_at, "@", scm_m_at);
407SCM_SYNTAX (s_atat, "@@", scm_m_atat);
bab98046 408SCM_SYNTAX (s_begin, "begin", scm_m_begin);
bab98046 409SCM_SYNTAX (s_define, "define", scm_m_define);
bb0229b5 410SCM_SYNTAX (s_with_fluids, "with-fluids", scm_m_with_fluids);
bab98046
AW
411SCM_SYNTAX (s_eval_when, "eval-when", scm_m_eval_when);
412SCM_SYNTAX (s_if, "if", scm_m_if);
413SCM_SYNTAX (s_lambda, "lambda", scm_m_lambda);
414SCM_SYNTAX (s_let, "let", scm_m_let);
bab98046
AW
415SCM_SYNTAX (s_quote, "quote", scm_m_quote);
416SCM_SYNTAX (s_set_x, "set!", scm_m_set_x);
b7742c6b 417
2cd72a84
AW
418/* Convenient syntax during boot, expands to primitive syntax. Replaced after
419 psyntax boots. */
420SCM_SYNTAX (s_and, "and", scm_m_and);
421SCM_SYNTAX (s_cond, "cond", scm_m_cond);
422SCM_SYNTAX (s_letrec, "letrec", scm_m_letrec);
423SCM_SYNTAX (s_letstar, "let*", scm_m_letstar);
424SCM_SYNTAX (s_or, "or", scm_m_or);
b7742c6b
AW
425
426SCM_GLOBAL_SYMBOL (scm_sym_apply, "apply");
427SCM_GLOBAL_SYMBOL (scm_sym_arrow, "=>");
428SCM_GLOBAL_SYMBOL (scm_sym_at, "@");
429SCM_GLOBAL_SYMBOL (scm_sym_atat, "@@");
430SCM_GLOBAL_SYMBOL (scm_sym_at_call_with_values, "@call-with-values");
431SCM_GLOBAL_SYMBOL (scm_sym_atapply, "@apply");
432SCM_GLOBAL_SYMBOL (scm_sym_atcall_cc, "@call-with-current-continuation");
433SCM_GLOBAL_SYMBOL (scm_sym_begin, "begin");
434SCM_GLOBAL_SYMBOL (scm_sym_case, "case");
435SCM_GLOBAL_SYMBOL (scm_sym_cond, "cond");
436SCM_GLOBAL_SYMBOL (scm_sym_define, "define");
d69531e2 437SCM_GLOBAL_SYMBOL (scm_sym_at_dynamic_wind, "@dynamic-wind");
bb0229b5 438SCM_GLOBAL_SYMBOL (scm_sym_with_fluids, "with-fluids");
b7742c6b
AW
439SCM_GLOBAL_SYMBOL (scm_sym_else, "else");
440SCM_GLOBAL_SYMBOL (scm_sym_eval_when, "eval-when");
441SCM_GLOBAL_SYMBOL (scm_sym_if, "if");
442SCM_GLOBAL_SYMBOL (scm_sym_lambda, "lambda");
443SCM_GLOBAL_SYMBOL (scm_sym_let, "let");
444SCM_GLOBAL_SYMBOL (scm_sym_letrec, "letrec");
445SCM_GLOBAL_SYMBOL (scm_sym_letstar, "let*");
446SCM_GLOBAL_SYMBOL (scm_sym_or, "or");
747022e4 447SCM_GLOBAL_SYMBOL (scm_sym_at_prompt, "@prompt");
b7742c6b
AW
448SCM_GLOBAL_SYMBOL (scm_sym_quote, "quote");
449SCM_GLOBAL_SYMBOL (scm_sym_set_x, "set!");
450SCM_SYMBOL (sym_eval, "eval");
451SCM_SYMBOL (sym_load, "load");
452
453SCM_GLOBAL_SYMBOL (scm_sym_unquote, "unquote");
454SCM_GLOBAL_SYMBOL (scm_sym_quasiquote, "quasiquote");
455SCM_GLOBAL_SYMBOL (scm_sym_uq_splicing, "unquote-splicing");
456
457
458static SCM
459scm_m_at (SCM expr, SCM env SCM_UNUSED)
460{
461 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
462 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
463 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
464
465 return MAKMEMO_MOD_REF (CADR (expr), CADDR (expr), SCM_BOOL_T);
466}
467
468static SCM
469scm_m_atat (SCM expr, SCM env SCM_UNUSED)
470{
471 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
472 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
473 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
474
475 return MAKMEMO_MOD_REF (CADR (expr), CADDR (expr), SCM_BOOL_F);
476}
477
478static SCM
479scm_m_and (SCM expr, SCM env)
480{
481 const SCM cdr_expr = CDR (expr);
482
483 if (scm_is_null (cdr_expr))
484 return MAKMEMO_QUOTE (SCM_BOOL_T);
485 ASSERT_SYNTAX (scm_is_pair (cdr_expr), s_bad_expression, expr);
486
487 if (scm_is_null (CDR (cdr_expr)))
488 return memoize (CAR (cdr_expr), env);
489 else
490 return MAKMEMO_IF (memoize (CAR (cdr_expr), env),
491 scm_m_and (cdr_expr, env),
492 MAKMEMO_QUOTE (SCM_BOOL_F));
493}
494
b7742c6b
AW
495static SCM
496scm_m_begin (SCM expr, SCM env)
497{
498 const SCM cdr_expr = CDR (expr);
499 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 1, s_bad_expression, expr);
500 return MAKMEMO_BEGIN (memoize_exprs (cdr_expr, env));
501}
502
b7742c6b
AW
503static SCM
504scm_m_cond (SCM expr, SCM env)
505{
506 /* Check, whether 'else or '=> is a literal, i. e. not bound to a value. */
507 const int else_literal_p = memoize_env_var_is_free (env, scm_sym_else);
508 const int arrow_literal_p = memoize_env_var_is_free (env, scm_sym_arrow);
509
510 const SCM clauses = CDR (expr);
511 SCM clause_idx;
512 SCM ret, loc;
513
514 ASSERT_SYNTAX (scm_ilength (clauses) >= 0, s_bad_expression, expr);
515 ASSERT_SYNTAX (scm_ilength (clauses) >= 1, s_missing_clauses, expr);
516
517 ret = scm_cons (SCM_UNDEFINED, MAKMEMO_QUOTE (SCM_UNSPECIFIED));
518 loc = ret;
519
520 for (clause_idx = clauses;
521 !scm_is_null (clause_idx);
522 clause_idx = CDR (clause_idx))
523 {
524 SCM test;
525
526 const SCM clause = CAR (clause_idx);
527 const long length = scm_ilength (clause);
528 ASSERT_SYNTAX_2 (length >= 1, s_bad_cond_clause, clause, expr);
529
530 test = CAR (clause);
531 if (scm_is_eq (test, scm_sym_else) && else_literal_p)
532 {
533 const int last_clause_p = scm_is_null (CDR (clause_idx));
534 ASSERT_SYNTAX_2 (length >= 2,
535 s_bad_cond_clause, clause, expr);
536 ASSERT_SYNTAX_2 (last_clause_p,
537 s_misplaced_else_clause, clause, expr);
538 SCM_SETCDR (loc,
539 memoize (scm_cons (scm_sym_begin, CDR (clause)), env));
540 }
541 else if (length >= 2
542 && scm_is_eq (CADR (clause), scm_sym_arrow)
543 && arrow_literal_p)
544 {
545 SCM tmp = scm_gensym (scm_from_locale_string ("cond "));
546 SCM i;
547 SCM new_env = scm_cons (tmp, env);
548 ASSERT_SYNTAX_2 (length > 2, s_missing_recipient, clause, expr);
549 ASSERT_SYNTAX_2 (length == 3, s_extra_expression, clause, expr);
550 i = MAKMEMO_IF (MAKMEMO_LEX_REF (0),
551 MAKMEMO_CALL (memoize (CADDR (clause),
552 scm_cons (tmp, new_env)),
9331f91c 553 1,
b7742c6b
AW
554 scm_list_1 (MAKMEMO_LEX_REF (0))),
555 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
556 SCM_SETCDR (loc,
557 MAKMEMO_LET (scm_list_1 (memoize (CAR (clause), env)),
558 i));
559 env = new_env;
560 loc = scm_last_pair (SCM_MEMOIZED_ARGS (i));
561 }
562 /* FIXME length == 1 case */
563 else
564 {
565 SCM i = MAKMEMO_IF (memoize (CAR (clause), env),
566 memoize (scm_cons (scm_sym_begin, CDR (clause)), env),
567 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
568 SCM_SETCDR (loc, i);
569 loc = scm_last_pair (SCM_MEMOIZED_ARGS (i));
570 }
571 }
572
573 return CDR (ret);
574}
575
576/* According to Section 5.2.1 of R5RS we first have to make sure that the
577 variable is bound, and then perform the `(set! variable expression)'
578 operation. However, EXPRESSION _can_ be evaluated before VARIABLE is
579 bound. This means that EXPRESSION won't necessarily be able to assign
580 values to VARIABLE as in `(define foo (begin (set! foo 1) (+ foo 1)))'. */
581static SCM
582scm_m_define (SCM expr, SCM env)
583{
584 const SCM cdr_expr = CDR (expr);
585 SCM body;
586 SCM variable;
587
588 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
589 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
590 ASSERT_SYNTAX (!scm_is_pair (env), s_bad_define, expr);
591
592 body = CDR (cdr_expr);
593 variable = CAR (cdr_expr);
594
595 if (scm_is_pair (variable))
596 {
597 ASSERT_SYNTAX_2 (scm_is_symbol (CAR (variable)), s_bad_variable, variable, expr);
598 return MAKMEMO_DEFINE (CAR (variable),
599 memoize (scm_cons (scm_sym_lambda,
600 scm_cons (CDR (variable), body)),
601 env));
602 }
603 ASSERT_SYNTAX_2 (scm_is_symbol (variable), s_bad_variable, variable, expr);
604 ASSERT_SYNTAX (scm_ilength (body) == 1, s_expression, expr);
605 return MAKMEMO_DEFINE (variable, memoize (CAR (body), env));
606}
607
bb0229b5
AW
608static SCM
609scm_m_with_fluids (SCM expr, SCM env)
610{
611 SCM binds, fluids, vals;
612 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
613 binds = CADR (expr);
614 ASSERT_SYNTAX_2 (scm_ilength (binds) >= 0, s_bad_bindings, binds, expr);
615 for (fluids = SCM_EOL, vals = SCM_EOL;
616 scm_is_pair (binds);
617 binds = CDR (binds))
618 {
619 SCM binding = CAR (binds);
620 ASSERT_SYNTAX_2 (scm_ilength (CAR (binds)) == 2, s_bad_binding,
621 binding, expr);
622 fluids = scm_cons (memoize (CAR (binding), env), fluids);
623 vals = scm_cons (memoize (CADR (binding), env), vals);
624 }
625
626 return MAKMEMO_WITH_FLUIDS (scm_reverse_x (fluids, SCM_UNDEFINED),
627 scm_reverse_x (vals, SCM_UNDEFINED),
628 memoize_sequence (CDDR (expr), env));
629}
630
b7742c6b
AW
631static SCM
632scm_m_eval_when (SCM expr, SCM env)
633{
634 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
635 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
636
637 if (scm_is_true (scm_memq (sym_eval, CADR (expr)))
638 || scm_is_true (scm_memq (sym_load, CADR (expr))))
639 return MAKMEMO_BEGIN (memoize_exprs (CDDR (expr), env));
640 else
641 return MAKMEMO_QUOTE (SCM_UNSPECIFIED);
642}
643
644static SCM
645scm_m_if (SCM expr, SCM env SCM_UNUSED)
646{
647 const SCM cdr_expr = CDR (expr);
648 const long length = scm_ilength (cdr_expr);
649 ASSERT_SYNTAX (length == 2 || length == 3, s_expression, expr);
650 return MAKMEMO_IF (memoize (CADR (expr), env),
651 memoize (CADDR (expr), env),
652 ((length == 3)
653 ? memoize (CADDDR (expr), env)
654 : MAKMEMO_QUOTE (SCM_UNSPECIFIED)));
655}
656
657/* A helper function for memoize_lambda to support checking for duplicate
658 * formal arguments: Return true if OBJ is `eq?' to one of the elements of
659 * LIST or to the CDR of the last cons. Therefore, LIST may have any of the
660 * forms that a formal argument can have:
661 * <rest>, (<arg1> ...), (<arg1> ... . <rest>) */
662static int
663c_improper_memq (SCM obj, SCM list)
664{
665 for (; scm_is_pair (list); list = CDR (list))
666 {
667 if (scm_is_eq (CAR (list), obj))
668 return 1;
669 }
670 return scm_is_eq (list, obj);
671}
672
673static SCM
674scm_m_lambda (SCM expr, SCM env SCM_UNUSED)
675{
676 SCM formals;
677 SCM formals_idx;
678 SCM formal_vars = SCM_EOL;
679 int nreq = 0;
680
681 const SCM cdr_expr = CDR (expr);
682 const long length = scm_ilength (cdr_expr);
683 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
684 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
685
686 /* Before iterating the list of formal arguments, make sure the formals
687 * actually are given as either a symbol or a non-cyclic list. */
688 formals = CAR (cdr_expr);
689 if (scm_is_pair (formals))
690 {
691 /* Dirk:FIXME:: We should check for a cyclic list of formals, and if
692 * detected, report a 'Bad formals' error. */
693 }
694 else
695 {
696 ASSERT_SYNTAX_2 (scm_is_symbol (formals) || scm_is_null (formals),
697 s_bad_formals, formals, expr);
698 }
699
700 /* Now iterate the list of formal arguments to check if all formals are
701 * symbols, and that there are no duplicates. */
702 formals_idx = formals;
703 while (scm_is_pair (formals_idx))
704 {
705 const SCM formal = CAR (formals_idx);
706 const SCM next_idx = CDR (formals_idx);
707 ASSERT_SYNTAX_2 (scm_is_symbol (formal), s_bad_formal, formal, expr);
708 ASSERT_SYNTAX_2 (!c_improper_memq (formal, next_idx),
709 s_duplicate_formal, formal, expr);
710 nreq++;
711 formal_vars = scm_cons (formal, formal_vars);
712 formals_idx = next_idx;
713 }
714 ASSERT_SYNTAX_2 (scm_is_null (formals_idx) || scm_is_symbol (formals_idx),
715 s_bad_formal, formals_idx, expr);
716 if (scm_is_symbol (formals_idx))
717 formal_vars = scm_cons (formals_idx, formal_vars);
718 return MAKMEMO_LAMBDA (nreq, scm_symbol_p (formals_idx),
719 memoize_sequence (CDDR (expr),
720 memoize_env_extend (env, formal_vars)));
721}
722
723/* Check if the format of the bindings is ((<symbol> <init-form>) ...). */
724static void
725check_bindings (const SCM bindings, const SCM expr)
726{
727 SCM binding_idx;
728
729 ASSERT_SYNTAX_2 (scm_ilength (bindings) >= 0,
730 s_bad_bindings, bindings, expr);
731
732 binding_idx = bindings;
733 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
734 {
735 SCM name; /* const */
736
737 const SCM binding = CAR (binding_idx);
738 ASSERT_SYNTAX_2 (scm_ilength (binding) == 2,
739 s_bad_binding, binding, expr);
740
741 name = CAR (binding);
742 ASSERT_SYNTAX_2 (scm_is_symbol (name), s_bad_variable, name, expr);
743 }
744}
745
746/* The bindings, which must have the format ((v1 i1) (v2 i2) ... (vn in)), are
747 * transformed to the lists (vn .. v2 v1) and (i1 i2 ... in). If a duplicate
748 * variable name is detected, an error is signalled. */
749static int
750transform_bindings (const SCM bindings, const SCM expr,
751 SCM *const rvarptr, SCM *const initptr)
752{
753 SCM rvariables = SCM_EOL;
754 SCM rinits = SCM_EOL;
755 SCM binding_idx = bindings;
756 int n = 0;
757 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
758 {
759 const SCM binding = CAR (binding_idx);
760 const SCM CDR_binding = CDR (binding);
761 const SCM name = CAR (binding);
762 ASSERT_SYNTAX_2 (scm_is_false (scm_c_memq (name, rvariables)),
763 s_duplicate_binding, name, expr);
764 rvariables = scm_cons (name, rvariables);
765 rinits = scm_cons (CAR (CDR_binding), rinits);
766 n++;
767 }
768 *rvarptr = rvariables;
769 *initptr = scm_reverse_x (rinits, SCM_UNDEFINED);
770 return n;
771}
772
773/* This function is a helper function for memoize_let. It transforms
774 * (let name ((var init) ...) body ...) into
775 * ((letrec ((name (lambda (var ...) body ...))) name) init ...)
776 * and memoizes the expression. It is assumed that the caller has checked
777 * that name is a symbol and that there are bindings and a body. */
778static SCM
779memoize_named_let (const SCM expr, SCM env)
780{
781 SCM rvariables;
782 SCM inits;
783 int nreq;
784
785 const SCM cdr_expr = CDR (expr);
786 const SCM name = CAR (cdr_expr);
787 const SCM cddr_expr = CDR (cdr_expr);
788 const SCM bindings = CAR (cddr_expr);
789 check_bindings (bindings, expr);
790
791 nreq = transform_bindings (bindings, expr, &rvariables, &inits);
792
793 env = scm_cons (name, env);
794 return MAKMEMO_LET
795 (scm_list_1 (MAKMEMO_QUOTE (SCM_UNDEFINED)),
796 MAKMEMO_BEGIN
797 (scm_list_2 (MAKMEMO_LEX_SET
798 (0,
799 MAKMEMO_LAMBDA
800 (nreq, SCM_BOOL_F,
801 memoize_sequence (CDDDR (expr),
802 memoize_env_extend (env, rvariables)))),
803 MAKMEMO_CALL (MAKMEMO_LEX_REF (0),
9331f91c 804 nreq,
b7742c6b
AW
805 memoize_exprs (inits, env)))));
806}
807
808/* (let ((v1 i1) (v2 i2) ...) body) with variables v1 .. vn and initializers
809 * i1 .. in is transformed to (#@let (vn ... v2 v1) (i1 i2 ...) body). */
810static SCM
811scm_m_let (SCM expr, SCM env)
812{
813 SCM bindings;
814
815 const SCM cdr_expr = CDR (expr);
816 const long length = scm_ilength (cdr_expr);
817 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
818 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
819
820 bindings = CAR (cdr_expr);
821 if (scm_is_symbol (bindings))
822 {
823 ASSERT_SYNTAX (length >= 3, s_missing_expression, expr);
824 return memoize_named_let (expr, env);
825 }
826
827 check_bindings (bindings, expr);
828 if (scm_is_null (bindings))
829 return memoize_sequence (CDDR (expr), env);
830 else
831 {
832 SCM rvariables;
833 SCM inits;
834 transform_bindings (bindings, expr, &rvariables, &inits);
835 return MAKMEMO_LET (memoize_exprs (inits, env),
836 memoize_sequence (CDDR (expr),
837 memoize_env_extend (env, rvariables)));
838 }
839}
840
841static SCM
842scm_m_letrec (SCM expr, SCM env)
843{
844 SCM bindings;
845
846 const SCM cdr_expr = CDR (expr);
847 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
848 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
849
850 bindings = CAR (cdr_expr);
851 if (scm_is_null (bindings))
852 return memoize_sequence (CDDR (expr), env);
853 else
854 {
855 SCM rvariables;
856 SCM inits;
857 SCM v, i;
858 SCM undefs = SCM_EOL;
859 SCM vals = SCM_EOL;
860 SCM sets = SCM_EOL;
861 SCM new_env;
862 int offset;
863 int n = transform_bindings (bindings, expr, &rvariables, &inits);
864 offset = n;
865 new_env = memoize_env_extend (env, rvariables);
866 for (v = scm_reverse (rvariables), i = inits; scm_is_pair (v);
867 v = CDR (v), i = CDR (i), n--)
868 {
869 undefs = scm_cons (MAKMEMO_QUOTE (SCM_UNDEFINED), undefs);
870 vals = scm_cons (memoize (CAR (i), new_env), vals);
871 sets = scm_cons (MAKMEMO_LEX_SET ((n-1) + offset,
872 MAKMEMO_LEX_REF (n-1)),
873 sets);
874 }
875 return MAKMEMO_LET
876 (undefs,
877 MAKMEMO_BEGIN (scm_list_2 (MAKMEMO_LET (scm_reverse (vals),
878 MAKMEMO_BEGIN (sets)),
879 memoize_sequence (CDDR (expr),
880 new_env))));
881 }
882}
883
884static SCM
885scm_m_letstar (SCM expr, SCM env SCM_UNUSED)
886{
887 SCM bindings;
888
889 const SCM cdr_expr = CDR (expr);
890 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
891 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
892
893 bindings = CAR (cdr_expr);
894 if (scm_is_null (bindings))
895 return memoize_sequence (CDDR (expr), env);
896 else
897 {
898 SCM rvariables;
899 SCM variables;
900 SCM inits;
901 SCM ret, loc;
902 transform_bindings (bindings, expr, &rvariables, &inits);
903 variables = scm_reverse (rvariables);
904 ret = scm_cons (SCM_UNDEFINED, SCM_UNSPECIFIED);
905 loc = ret;
906 for (; scm_is_pair (variables);
907 variables = CDR (variables), inits = CDR (inits))
908 { SCM x = MAKMEMO_LET (scm_list_1 (memoize (CAR (inits), env)),
909 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
910 SCM_SETCDR (loc, x);
911 loc = scm_last_pair (SCM_MEMOIZED_ARGS (x));
912 env = scm_cons (CAR (variables), env);
913 }
914 SCM_SETCDR (loc, memoize_sequence (CDDR (expr), env));
915 return CDR (ret);
916 }
917}
918
919static SCM
920scm_m_or (SCM expr, SCM env SCM_UNUSED)
921{
922 SCM tail = CDR (expr);
923 SCM ret, loc;
924 const long length = scm_ilength (tail);
925
926 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
927
928 ret = scm_cons (SCM_UNDEFINED, SCM_UNSPECIFIED);
929 loc = ret;
930 for (; scm_is_pair (tail); tail = CDR (tail))
931 {
932 SCM tmp = scm_gensym (scm_from_locale_string ("cond "));
933 SCM x = MAKMEMO_IF (MAKMEMO_LEX_REF (0),
934 MAKMEMO_LEX_REF (0),
935 MAKMEMO_QUOTE (SCM_UNSPECIFIED));
936 SCM new_env = scm_cons (tmp, env);
937 SCM_SETCDR (loc, MAKMEMO_LET (scm_list_1 (memoize (CAR (tail),
938 env)),
939 x));
940 env = new_env;
941 loc = scm_last_pair (SCM_MEMOIZED_ARGS (x));
942 }
943 SCM_SETCDR (loc, MAKMEMO_QUOTE (SCM_BOOL_F));
944 return CDR (ret);
945}
946
947static SCM
948scm_m_quote (SCM expr, SCM env SCM_UNUSED)
949{
950 SCM quotee;
951
952 const SCM cdr_expr = CDR (expr);
953 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
954 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 1, s_expression, expr);
955 quotee = CAR (cdr_expr);
956 return MAKMEMO_QUOTE (quotee);
957}
958
959static SCM
960scm_m_set_x (SCM expr, SCM env)
961{
962 SCM variable;
963 SCM vmem;
964
965 const SCM cdr_expr = CDR (expr);
966 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
967 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 2, s_expression, expr);
968 variable = CAR (cdr_expr);
969 vmem = memoize (variable, env);
970
971 switch (SCM_MEMOIZED_TAG (vmem))
972 {
973 case SCM_M_LEXICAL_REF:
974 return MAKMEMO_LEX_SET (SCM_I_INUM (SCM_MEMOIZED_ARGS (vmem)),
975 memoize (CADDR (expr), env));
976 case SCM_M_TOPLEVEL_REF:
977 return MAKMEMO_TOP_SET (variable,
978 memoize (CADDR (expr), env));
979 case SCM_M_MODULE_REF:
980 return MAKMEMO_MOD_SET (memoize (CADDR (expr), env),
981 CAR (SCM_MEMOIZED_ARGS (vmem)),
982 CADR (SCM_MEMOIZED_ARGS (vmem)),
983 CDDR (SCM_MEMOIZED_ARGS (vmem)));
984 default:
985 syntax_error (s_bad_variable, variable, expr);
986 }
987}
988
989
990\f
991
992SCM_DEFINE (scm_memoize_expression, "memoize-expression", 1, 0, 0,
993 (SCM exp),
994 "Memoize the expression @var{exp}.")
995#define FUNC_NAME s_scm_memoize_expression
996{
997 return memoize (exp, scm_current_module ());
998}
999#undef FUNC_NAME
1000
2cd72a84 1001
b7742c6b
AW
1002\f
1003
2cd72a84
AW
1004#define SCM_MAKE_MEMOIZER(STR, MEMOIZER, N) \
1005 (scm_cell (scm_tc16_memoizer, \
1006 (scm_t_bits)(scm_c_make_gsubr (STR, N, 0, 0, MEMOIZER))))
1007#define SCM_DEFINE_MEMOIZER(STR, MEMOIZER, N) \
1008SCM_SNARF_INIT(scm_c_define (STR, SCM_MAKE_MEMOIZER (STR, MEMOIZER, N)))
1009
1010static SCM m_apply (SCM proc, SCM args);
1011static SCM m_call_cc (SCM proc);
1012static SCM m_call_values (SCM prod, SCM cons);
1013static SCM m_dynamic_wind (SCM pre, SCM exp, SCM post);
1014static SCM m_prompt (SCM tag, SCM exp, SCM handler);
1015
1016SCM_DEFINE_MEMOIZER ("@apply", m_apply, 2);
1017SCM_DEFINE_MEMOIZER ("@call-with-current-continuation", m_call_cc, 1);
1018SCM_DEFINE_MEMOIZER ("@call-with-values", m_call_values, 2);
1019SCM_DEFINE_MEMOIZER ("@dynamic-wind", m_dynamic_wind, 3);
1020SCM_DEFINE_MEMOIZER ("@prompt", m_prompt, 3);
1021
1022
1023\f
1024
1025static SCM m_apply (SCM proc, SCM args)
1026#define FUNC_NAME "@apply"
1027{
1028 SCM_VALIDATE_MEMOIZED (1, proc);
1029 SCM_VALIDATE_MEMOIZED (2, args);
1030 return MAKMEMO_APPLY (proc, args);
1031}
1032#undef FUNC_NAME
1033
1034static SCM m_call_cc (SCM proc)
1035#define FUNC_NAME "@call-with-current-continuation"
1036{
1037 SCM_VALIDATE_MEMOIZED (1, proc);
1038 return MAKMEMO_CONT (proc);
1039}
1040#undef FUNC_NAME
1041
1042static SCM m_call_values (SCM prod, SCM cons)
1043#define FUNC_NAME "@call-with-values"
1044{
1045 SCM_VALIDATE_MEMOIZED (1, prod);
1046 SCM_VALIDATE_MEMOIZED (2, cons);
1047 return MAKMEMO_CALL_WITH_VALUES (prod, cons);
1048}
1049#undef FUNC_NAME
1050
1051static SCM m_dynamic_wind (SCM in, SCM expr, SCM out)
1052#define FUNC_NAME "memoize-dynwind"
1053{
1054 SCM_VALIDATE_MEMOIZED (1, in);
1055 SCM_VALIDATE_MEMOIZED (2, expr);
1056 SCM_VALIDATE_MEMOIZED (3, out);
1057 return MAKMEMO_DYNWIND (in, expr, out);
1058}
1059#undef FUNC_NAME
1060
1061static SCM m_prompt (SCM tag, SCM exp, SCM handler)
1062#define FUNC_NAME "@prompt"
1063{
1064 SCM_VALIDATE_MEMOIZED (1, tag);
1065 SCM_VALIDATE_MEMOIZED (2, exp);
1066 SCM_VALIDATE_MEMOIZED (3, handler);
1067 return MAKMEMO_PROMPT (tag, exp, handler);
1068}
1069#undef FUNC_NAME
1070
1071SCM_DEFINE (scm_memoizer_p, "memoizer?", 1, 0, 0,
1072 (SCM x), "")
1073{
1074 return scm_from_bool (SCM_MEMOIZER_P (x));
1075}
1076
1077SCM_DEFINE (scm_memoizer, "memoizer", 1, 0, 0,
1078 (SCM memoizer), "")
1079{
1080 SCM_ASSERT (SCM_MEMOIZER_P (memoizer), memoizer, 1, "memoizer?");
1081 return SCM_MEMOIZER (memoizer);
1082}
1083
1084
1085\f
b7742c6b 1086
384012a1
AW
1087#define SCM_VALIDATE_MEMOIZED_LIST(n, exps) \
1088 { \
1089 SCM walk; \
1090 for (walk = exps; scm_is_pair (walk); walk = scm_cdr (walk)) \
1091 SCM_ASSERT (SCM_MEMOIZED_P (scm_car (walk)), exps, n, FUNC_NAME); \
1092 SCM_ASSERT (scm_is_null (walk), exps, n, FUNC_NAME); \
1093 }
1094
1095SCM_DEFINE (scm_memoize_begin, "memoize-begin", 1, 0, 0,
1096 (SCM exps), "")
1097#define FUNC_NAME s_scm_memoize_begin
1098{
1099 SCM_VALIDATE_MEMOIZED_LIST (1, exps);
1100 return MAKMEMO_BEGIN (exps);
1101}
1102#undef FUNC_NAME
1103
1104SCM_DEFINE (scm_memoize_if, "memoize-if", 3, 0, 0,
1105 (SCM test, SCM then, SCM else_), "")
1106#define FUNC_NAME s_scm_memoize_if
1107{
1108 SCM_VALIDATE_MEMOIZED (1, test);
1109 SCM_VALIDATE_MEMOIZED (2, then);
1110 SCM_VALIDATE_MEMOIZED (3, else_);
1111 return MAKMEMO_IF (test, then, else_);
1112}
1113#undef FUNC_NAME
1114
1115SCM_DEFINE (scm_memoize_lambda, "memoize-lambda", 3, 0, 0,
1116 (SCM nreq, SCM rest, SCM body), "")
1117#define FUNC_NAME s_scm_memoize_lambda
1118{
1119 SCM_VALIDATE_BOOL (2, rest);
1120 SCM_VALIDATE_MEMOIZED (3, body);
1121 return MAKMEMO_LAMBDA (scm_to_uint16 (nreq), rest, body);
1122}
1123#undef FUNC_NAME
1124
1125SCM_DEFINE (scm_memoize_let, "memoize-let", 2, 0, 0,
1126 (SCM inits, SCM body), "")
1127#define FUNC_NAME s_scm_memoize_let
1128{
1129 SCM_VALIDATE_MEMOIZED_LIST (1, inits);
1130 SCM_VALIDATE_MEMOIZED (2, body);
1131 return MAKMEMO_LET (inits, body);
1132}
1133#undef FUNC_NAME
1134
1135SCM_DEFINE (scm_memoize_quote, "memoize-quote", 1, 0, 0,
1136 (SCM exp), "")
1137#define FUNC_NAME s_scm_memoize_quote
1138{
1139 return MAKMEMO_QUOTE (exp);
1140}
1141#undef FUNC_NAME
1142
1143SCM_DEFINE (scm_memoize_define, "memoize-define", 2, 0, 0,
1144 (SCM var, SCM val), "")
1145#define FUNC_NAME s_scm_memoize_define
1146{
1147 SCM_VALIDATE_SYMBOL (1, var);
1148 SCM_VALIDATE_MEMOIZED (2, val);
1149 return MAKMEMO_DEFINE (var, val);
1150}
1151#undef FUNC_NAME
1152
1153SCM_DEFINE (scm_memoize_with_fluids, "memoize-with-fluids", 3, 0, 0,
1154 (SCM fluids, SCM vals, SCM expr), "")
1155#define FUNC_NAME s_scm_memoize_with_fluids
1156{
1157 SCM_VALIDATE_MEMOIZED_LIST (1, fluids);
1158 SCM_VALIDATE_MEMOIZED_LIST (2, vals);
1159 SCM_ASSERT (scm_ilength (fluids) == scm_ilength (vals), vals, 2, FUNC_NAME);
1160 SCM_VALIDATE_MEMOIZED (3, expr);
1161 return MAKMEMO_WITH_FLUIDS (fluids, vals, expr);
1162}
1163#undef FUNC_NAME
1164
1165SCM_DEFINE (scm_memoize_call, "memoize-call", 3, 0, 0,
1166 (SCM proc, SCM nargs, SCM args), "")
1167#define FUNC_NAME s_scm_memoize_call
1168{
1169 SCM_VALIDATE_MEMOIZED (1, proc);
1170 SCM_VALIDATE_MEMOIZED_LIST (3, args);
1171 return MAKMEMO_CALL (proc, scm_to_uint16 (nargs), args);
1172}
1173#undef FUNC_NAME
1174
1175SCM_DEFINE (scm_memoize_lexical_ref, "memoize-lexical-ref", 1, 0, 0,
1176 (SCM n), "")
1177#define FUNC_NAME s_scm_memoize_lexical_ref
1178{
1179 return MAKMEMO_LEX_REF (scm_to_uint16 (n));
1180}
1181#undef FUNC_NAME
1182
1183SCM_DEFINE (scm_memoize_lexical_set, "memoize-lexical-set!", 2, 0, 0,
1184 (SCM n, SCM val), "")
1185#define FUNC_NAME s_scm_memoize_lexical_set
1186{
1187 SCM_VALIDATE_MEMOIZED (1, val);
1188 return MAKMEMO_LEX_SET (n, val);
1189}
1190#undef FUNC_NAME
1191
1192SCM_DEFINE (scm_memoize_toplevel_ref, "memoize-toplevel-ref", 1, 0, 0,
1193 (SCM var), "")
1194#define FUNC_NAME s_scm_memoize_toplevel_ref
1195{
1196 SCM_VALIDATE_SYMBOL (1, var);
1197 return MAKMEMO_TOP_REF (var);
1198}
1199#undef FUNC_NAME
1200
1201SCM_DEFINE (scm_memoize_toplevel_set, "memoize-toplevel-set!", 2, 0, 0,
1202 (SCM var, SCM val), "")
1203#define FUNC_NAME s_scm_memoize_toplevel_set
1204{
1205 SCM_VALIDATE_SYMBOL (1, var);
1206 SCM_VALIDATE_MEMOIZED (2, val);
1207 return MAKMEMO_TOP_SET (var, val);
1208}
1209#undef FUNC_NAME
1210
1211SCM_DEFINE (scm_memoize_module_ref, "memoize-module-ref", 3, 0, 0,
1212 (SCM mod, SCM var, SCM public), "")
1213#define FUNC_NAME s_scm_memoize_module_ref
1214{
1215 SCM_VALIDATE_SYMBOL (2, var);
1216 SCM_VALIDATE_BOOL (3, public);
1217 return MAKMEMO_MOD_REF (mod, var, public);
1218}
1219#undef FUNC_NAME
1220
1221SCM_DEFINE (scm_memoize_module_set, "memoize-module-set!", 4, 0, 0,
1222 (SCM val, SCM mod, SCM var, SCM public), "")
1223#define FUNC_NAME s_scm_memoize_module_set
1224{
1225 SCM_VALIDATE_MEMOIZED (1, val);
1226 SCM_VALIDATE_SYMBOL (3, var);
1227 SCM_VALIDATE_BOOL (4, public);
1228 return MAKMEMO_MOD_SET (val, mod, var, public);
1229}
1230#undef FUNC_NAME
1231
1232
1233\f
1234
b7742c6b
AW
1235SCM_SYMBOL (sym_placeholder, "_");
1236
1237static SCM unmemoize (SCM expr);
1238
1239static SCM
1240unmemoize_exprs (SCM exprs)
1241{
1242 SCM ret, tail;
1243 if (scm_is_null (exprs))
1244 return SCM_EOL;
1245 ret = scm_list_1 (unmemoize (CAR (exprs)));
1246 tail = ret;
1247 for (exprs = CDR (exprs); !scm_is_null (exprs); exprs = CDR (exprs))
1248 {
1249 SCM_SETCDR (tail, scm_list_1 (unmemoize (CAR (exprs))));
1250 tail = CDR (tail);
1251 }
1252 return ret;
1253}
1254
1255static SCM
1256unmemoize_bindings (SCM inits)
1257{
1258 SCM ret, tail;
1259 if (scm_is_null (inits))
1260 return SCM_EOL;
1261 ret = scm_list_1 (scm_list_2 (sym_placeholder, unmemoize (CAR (inits))));
1262 tail = ret;
1263 for (inits = CDR (inits); !scm_is_null (inits); inits = CDR (inits))
1264 {
1265 SCM_SETCDR (tail, scm_list_1 (scm_list_2 (sym_placeholder,
1266 unmemoize (CAR (inits)))));
1267 tail = CDR (tail);
1268 }
1269 return ret;
1270}
1271
1272static SCM
1273unmemoize_lexical (SCM n)
1274{
1275 char buf[16];
1276 buf[15] = 0;
1277 snprintf (buf, 15, "<%u>", scm_to_uint32 (n));
1278 return scm_from_locale_symbol (buf);
1279}
1280
1281static SCM
1282unmemoize (const SCM expr)
1283{
1284 SCM args;
1285
1286 if (!SCM_MEMOIZED_P (expr))
1287 abort ();
1288
1289 args = SCM_MEMOIZED_ARGS (expr);
1290 switch (SCM_MEMOIZED_TAG (expr))
1291 {
1292 case SCM_M_APPLY:
1293 return scm_cons (scm_sym_atapply, unmemoize_exprs (args));
1294 case SCM_M_BEGIN:
1295 return scm_cons (scm_sym_begin, unmemoize_exprs (args));
1296 case SCM_M_CALL:
9331f91c 1297 return scm_cons (unmemoize (CAR (args)), unmemoize_exprs (CDDR (args)));
b7742c6b
AW
1298 case SCM_M_CONT:
1299 return scm_list_2 (scm_sym_atcall_cc, unmemoize (args));
1300 case SCM_M_CALL_WITH_VALUES:
1301 return scm_list_3 (scm_sym_at_call_with_values,
1302 unmemoize (CAR (args)), unmemoize (CDR (args)));
1303 case SCM_M_DEFINE:
1304 return scm_list_3 (scm_sym_define, CAR (args), unmemoize (CDR (args)));
d69531e2
AW
1305 case SCM_M_DYNWIND:
1306 return scm_list_4 (scm_sym_at_dynamic_wind,
1307 unmemoize (CAR (args)),
1308 unmemoize (CADR (args)),
1309 unmemoize (CDDR (args)));
bb0229b5
AW
1310 case SCM_M_WITH_FLUIDS:
1311 {
1312 SCM binds = SCM_EOL, fluids, vals;
1313 for (fluids = CAR (args), vals = CADR (args); scm_is_pair (fluids);
1314 fluids = CDR (fluids), vals = CDR (vals))
1315 binds = scm_cons (scm_list_2 (unmemoize (CAR (fluids)),
1316 unmemoize (CAR (vals))),
1317 binds);
1318 return scm_list_3 (scm_sym_with_fluids,
1319 scm_reverse_x (binds, SCM_UNDEFINED),
1320 unmemoize (CDDR (args)));
1321 }
b7742c6b
AW
1322 case SCM_M_IF:
1323 return scm_list_4 (scm_sym_if, unmemoize (scm_car (args)),
1324 unmemoize (scm_cadr (args)), unmemoize (scm_cddr (args)));
1325 case SCM_M_LAMBDA:
1326 return scm_list_3 (scm_sym_lambda,
1327 scm_make_list (CAR (args), sym_placeholder),
1328 unmemoize (CDDR (args)));
1329 case SCM_M_LET:
1330 return scm_list_3 (scm_sym_let,
1331 unmemoize_bindings (CAR (args)),
1332 unmemoize (CDR (args)));
1333 case SCM_M_QUOTE:
1334 return scm_list_2 (scm_sym_quote, args);
1335 case SCM_M_LEXICAL_REF:
1336 return unmemoize_lexical (args);
1337 case SCM_M_LEXICAL_SET:
1338 return scm_list_3 (scm_sym_set_x, unmemoize_lexical (CAR (args)),
1339 unmemoize (CDR (args)));
1340 case SCM_M_TOPLEVEL_REF:
1341 return args;
1342 case SCM_M_TOPLEVEL_SET:
1343 return scm_list_3 (scm_sym_set_x, CAR (args), unmemoize (CDR (args)));
1344 case SCM_M_MODULE_REF:
c08899ff
AW
1345 return SCM_VARIABLEP (args) ? args
1346 : scm_list_3 (scm_is_true (CDDR (args)) ? scm_sym_at : scm_sym_atat,
1347 scm_i_finite_list_copy (CAR (args)),
1348 CADR (args));
b7742c6b
AW
1349 case SCM_M_MODULE_SET:
1350 return scm_list_3 (scm_sym_set_x,
c08899ff
AW
1351 SCM_VARIABLEP (CDR (args)) ? CDR (args)
1352 : scm_list_3 (scm_is_true (CDDDR (args))
1353 ? scm_sym_at : scm_sym_atat,
1354 scm_i_finite_list_copy (CADR (args)),
1355 CADDR (args)),
b7742c6b 1356 unmemoize (CAR (args)));
747022e4
AW
1357 case SCM_M_PROMPT:
1358 return scm_list_4 (scm_sym_at_prompt,
1359 unmemoize (CAR (args)),
1360 unmemoize (CADR (args)),
1361 unmemoize (CDDR (args)));
b7742c6b
AW
1362 default:
1363 abort ();
1364 }
1365}
1366
2cd72a84
AW
1367
1368\f
1369
b7742c6b
AW
1370SCM_DEFINE (scm_memoized_p, "memoized?", 1, 0, 0,
1371 (SCM obj),
1372 "Return @code{#t} if @var{obj} is memoized.")
1373#define FUNC_NAME s_scm_memoized_p
1374{
1375 return scm_from_bool (SCM_MEMOIZED_P (obj));
1376}
1377#undef FUNC_NAME
1378
1379SCM_DEFINE (scm_unmemoize_expression, "unmemoize-expression", 1, 0, 0,
1380 (SCM m),
1381 "Unmemoize the memoized expression @var{m}.")
1382#define FUNC_NAME s_scm_unmemoize_expression
1383{
1384 SCM_VALIDATE_MEMOIZED (1, m);
1385 return unmemoize (m);
1386}
1387#undef FUNC_NAME
1388
3149a5b6
AW
1389SCM_DEFINE (scm_memoized_expression_typecode, "memoized-expression-typecode", 1, 0, 0,
1390 (SCM m),
1391 "Return the typecode from the memoized expression @var{m}.")
1392#define FUNC_NAME s_scm_memoized_expression_typecode
1393{
1394 SCM_VALIDATE_MEMOIZED (1, m);
b7ecadca
LC
1395
1396 /* The tag is a 16-bit integer so it fits in an inum. */
1397 return SCM_I_MAKINUM (SCM_MEMOIZED_TAG (m));
3149a5b6
AW
1398}
1399#undef FUNC_NAME
1400
1401SCM_DEFINE (scm_memoized_expression_data, "memoized-expression-data", 1, 0, 0,
1402 (SCM m),
1403 "Return the data from the memoized expression @var{m}.")
1404#define FUNC_NAME s_scm_memoized_expression_data
1405{
1406 SCM_VALIDATE_MEMOIZED (1, m);
1407 return SCM_MEMOIZED_ARGS (m);
1408}
1409#undef FUNC_NAME
1410
1411SCM_DEFINE (scm_memoized_typecode, "memoized-typecode", 1, 0, 0,
1412 (SCM sym),
1413 "Return the memoized typecode corresponding to the symbol @var{sym}.")
1414#define FUNC_NAME s_scm_memoized_typecode
1415{
1416 int i;
1417
1418 SCM_VALIDATE_SYMBOL (1, sym);
1419
1420 for (i = 0; i < sizeof(memoized_tags)/sizeof(const char*); i++)
1421 if (strcmp (scm_i_symbol_chars (sym), memoized_tags[i]) == 0)
1422 return scm_from_int32 (i);
1423
1424 return SCM_BOOL_F;
1425}
1426#undef FUNC_NAME
1427
1428SCM_SYMBOL (scm_unbound_variable_key, "unbound-variable");
1429static void error_unbound_variable (SCM symbol) SCM_NORETURN;
1430static void error_unbound_variable (SCM symbol)
1431{
1432 scm_error (scm_unbound_variable_key, NULL, "Unbound variable: ~S",
1433 scm_list_1 (symbol), SCM_BOOL_F);
1434}
1435
1436SCM_DEFINE (scm_memoize_variable_access_x, "memoize-variable-access!", 2, 0, 0,
1437 (SCM m, SCM mod),
1438 "Look up and cache the variable that @var{m} will access, returning the variable.")
7230aaf9 1439#define FUNC_NAME s_scm_memoize_variable_access_x
3149a5b6
AW
1440{
1441 SCM mx;
1442 SCM_VALIDATE_MEMOIZED (1, m);
1443 mx = SCM_MEMOIZED_ARGS (m);
1444 switch (SCM_MEMOIZED_TAG (m))
1445 {
1446 case SCM_M_TOPLEVEL_REF:
1447 if (SCM_VARIABLEP (mx))
1448 return mx;
1449 else
1450 {
1451 SCM var = scm_module_variable (mod, mx);
1452 if (scm_is_false (var) || scm_is_false (scm_variable_bound_p (var)))
1453 error_unbound_variable (mx);
1454 SCM_SET_SMOB_OBJECT (m, var);
1455 return var;
1456 }
1457
1458 case SCM_M_TOPLEVEL_SET:
1459 {
1460 SCM var = CAR (mx);
1461 if (SCM_VARIABLEP (var))
1462 return var;
1463 else
1464 {
1465 var = scm_module_variable (mod, var);
1466 if (scm_is_false (var))
1467 error_unbound_variable (CAR (mx));
1468 SCM_SETCAR (mx, var);
1469 return var;
1470 }
1471 }
1472
1473 case SCM_M_MODULE_REF:
1474 if (SCM_VARIABLEP (mx))
1475 return mx;
1476 else
1477 {
1478 SCM var;
1479 mod = scm_resolve_module (CAR (mx));
1480 if (scm_is_true (CDDR (mx)))
1481 mod = scm_module_public_interface (mod);
1482 var = scm_module_lookup (mod, CADR (mx));
1483 if (scm_is_false (scm_variable_bound_p (var)))
1484 error_unbound_variable (CADR (mx));
1485 SCM_SET_SMOB_OBJECT (m, var);
1486 return var;
1487 }
1488
1489 case SCM_M_MODULE_SET:
1490 /* FIXME: not quite threadsafe */
1491 if (SCM_VARIABLEP (CDR (mx)))
1492 return CDR (mx);
1493 else
1494 {
1495 SCM var;
1496 mod = scm_resolve_module (CADR (mx));
1497 if (scm_is_true (CDDDR (mx)))
1498 mod = scm_module_public_interface (mod);
1499 var = scm_module_lookup (mod, CADDR (mx));
1500 SCM_SETCDR (mx, var);
1501 return var;
1502 }
1503
1504 default:
1505 scm_wrong_type_arg (FUNC_NAME, 1, m);
1506 return SCM_BOOL_F;
1507 }
1508}
1509#undef FUNC_NAME
1510
b7742c6b
AW
1511
1512\f
1513
1514void
1515scm_init_memoize ()
1516{
1517 scm_tc16_memoized = scm_make_smob_type ("%memoized", 0);
1518 scm_set_smob_mark (scm_tc16_memoized, scm_markcdr);
1519 scm_set_smob_print (scm_tc16_memoized, scm_print_memoized);
1520
2cd72a84
AW
1521 scm_tc16_memoizer = scm_make_smob_type ("memoizer", 0);
1522
b7742c6b 1523#include "libguile/memoize.x"
4f692ace
AW
1524
1525 scm_c_define ("macroexpand",
1526 scm_variable_ref (scm_c_lookup ("memoize-expression")));
b7742c6b
AW
1527}
1528
1529/*
1530 Local Variables:
1531 c-file-style: "gnu"
1532 End:
1533*/