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