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