fix scm_protects deprecation warning
[bpt/guile.git] / libguile / expand.c
1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
2 * Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20 \f
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "libguile/__scm.h"
27 #include "libguile/_scm.h"
28 #include "libguile/continuations.h"
29 #include "libguile/eq.h"
30 #include "libguile/list.h"
31 #include "libguile/macros.h"
32 #include "libguile/expand.h"
33 #include "libguile/modules.h"
34 #include "libguile/srcprop.h"
35 #include "libguile/ports.h"
36 #include "libguile/print.h"
37 #include "libguile/strings.h"
38 #include "libguile/throw.h"
39 #include "libguile/validate.h"
40
41
42 \f
43
44
45 SCM scm_exp_vtable_vtable;
46 static SCM exp_vtables[SCM_NUM_EXPANDED_TYPES];
47 static size_t exp_nfields[SCM_NUM_EXPANDED_TYPES];
48 static const char* exp_names[SCM_NUM_EXPANDED_TYPES];
49 static const char** exp_field_names[SCM_NUM_EXPANDED_TYPES];
50
51
52 #define VOID(src) \
53 SCM_MAKE_EXPANDED_VOID(src)
54 #define CONST(src, exp) \
55 SCM_MAKE_EXPANDED_CONST(src, exp)
56 #define PRIMITIVE_REF_TYPE(src, name) \
57 SCM_MAKE_EXPANDED_PRIMITIVE_REF_TYPE(src, name)
58 #define LEXICAL_REF(src, name, gensym) \
59 SCM_MAKE_EXPANDED_LEXICAL_REF(src, name, gensym)
60 #define LEXICAL_SET(src, name, gensym, exp) \
61 SCM_MAKE_EXPANDED_LEXICAL_SET(src, name, gensym, exp)
62 #define MODULE_REF(src, mod, name, public) \
63 SCM_MAKE_EXPANDED_MODULE_REF(src, mod, name, public)
64 #define MODULE_SET(src, mod, name, public, exp) \
65 SCM_MAKE_EXPANDED_MODULE_SET(src, mod, name, public, exp)
66 #define TOPLEVEL_REF(src, name) \
67 SCM_MAKE_EXPANDED_TOPLEVEL_REF(src, name)
68 #define TOPLEVEL_SET(src, name, exp) \
69 SCM_MAKE_EXPANDED_TOPLEVEL_SET(src, name, exp)
70 #define TOPLEVEL_DEFINE(src, name, exp) \
71 SCM_MAKE_EXPANDED_TOPLEVEL_DEFINE(src, name, exp)
72 #define CONDITIONAL(src, test, consequent, alternate) \
73 SCM_MAKE_EXPANDED_CONDITIONAL(src, test, consequent, alternate)
74 #define APPLICATION(src, proc, exps) \
75 SCM_MAKE_EXPANDED_APPLICATION(src, proc, exps)
76 #define SEQUENCE(src, exps) \
77 SCM_MAKE_EXPANDED_SEQUENCE(src, exps)
78 #define LAMBDA(src, meta, body) \
79 SCM_MAKE_EXPANDED_LAMBDA(src, meta, body)
80 #define LAMBDA_CASE(src, req, opt, rest, kw, inits, gensyms, body, alternate) \
81 SCM_MAKE_EXPANDED_LAMBDA_CASE(src, req, opt, rest, kw, inits, gensyms, body, alternate)
82 #define LET(src, names, gensyms, vals, body) \
83 SCM_MAKE_EXPANDED_LET(src, names, gensyms, vals, body)
84 #define LETREC(src, in_order_p, names, gensyms, vals, body) \
85 SCM_MAKE_EXPANDED_LETREC(src, in_order_p, names, gensyms, vals, body)
86 #define DYNLET(src, fluids, vals, body) \
87 SCM_MAKE_EXPANDED_DYNLET(src, fluids, vals, body)
88
89 #define CAR(x) SCM_CAR(x)
90 #define CDR(x) SCM_CDR(x)
91 #define CAAR(x) SCM_CAAR(x)
92 #define CADR(x) SCM_CADR(x)
93 #define CDAR(x) SCM_CDAR(x)
94 #define CDDR(x) SCM_CDDR(x)
95 #define CADDR(x) SCM_CADDR(x)
96 #define CDDDR(x) SCM_CDDDR(x)
97 #define CADDDR(x) SCM_CADDDR(x)
98
99
100 static const char s_bad_expression[] = "Bad expression";
101 static const char s_expression[] = "Missing or extra expression in";
102 static const char s_missing_expression[] = "Missing expression in";
103 static const char s_extra_expression[] = "Extra expression in";
104 static const char s_empty_combination[] = "Illegal empty combination";
105 static const char s_missing_body_expression[] = "Missing body expression in";
106 static const char s_mixed_body_forms[] = "Mixed definitions and expressions in";
107 static const char s_bad_define[] = "Bad define placement";
108 static const char s_missing_clauses[] = "Missing clauses";
109 static const char s_misplaced_else_clause[] = "Misplaced else clause";
110 static const char s_bad_case_clause[] = "Bad case clause";
111 static const char s_bad_case_labels[] = "Bad case labels";
112 static const char s_duplicate_case_label[] = "Duplicate case label";
113 static const char s_bad_cond_clause[] = "Bad cond clause";
114 static const char s_missing_recipient[] = "Missing recipient in";
115 static const char s_bad_variable[] = "Bad variable";
116 static const char s_bad_bindings[] = "Bad bindings";
117 static const char s_bad_binding[] = "Bad binding";
118 static const char s_duplicate_binding[] = "Duplicate binding";
119 static const char s_bad_exit_clause[] = "Bad exit clause";
120 static const char s_bad_formals[] = "Bad formals";
121 static const char s_bad_formal[] = "Bad formal";
122 static const char s_duplicate_formal[] = "Duplicate formal";
123 static const char s_splicing[] = "Non-list result for unquote-splicing";
124 static const char s_bad_slot_number[] = "Bad slot number";
125
126 static void syntax_error (const char* const, const SCM, const SCM) SCM_NORETURN;
127
128 SCM_SYMBOL (syntax_error_key, "syntax-error");
129
130 /* Shortcut macros to simplify syntax error handling. */
131 #define ASSERT_SYNTAX(cond, message, form) \
132 { if (SCM_UNLIKELY (!(cond))) \
133 syntax_error (message, form, SCM_UNDEFINED); }
134 #define ASSERT_SYNTAX_2(cond, message, form, expr) \
135 { if (SCM_UNLIKELY (!(cond))) \
136 syntax_error (message, form, expr); }
137
138
139 \f
140
141 /* Primitive syntax. */
142
143 #define SCM_SYNTAX(STR, CFN) \
144 SCM_SNARF_HERE(static SCM CFN (SCM xorig, SCM env)) \
145 SCM_SNARF_INIT(scm_c_define (STR, scm_i_make_primitive_macro (STR, CFN)))
146
147
148 /* True primitive syntax */
149 SCM_SYNTAX ("@", expand_at);
150 SCM_SYNTAX ("@@", expand_atat);
151 SCM_SYNTAX ("begin", expand_begin);
152 SCM_SYNTAX ("define", expand_define);
153 SCM_SYNTAX ("with-fluids", expand_with_fluids);
154 SCM_SYNTAX ("eval-when", expand_eval_when);
155 SCM_SYNTAX ("if", expand_if);
156 SCM_SYNTAX ("lambda", expand_lambda);
157 SCM_SYNTAX ("let", expand_let);
158 SCM_SYNTAX ("quote", expand_quote);
159 SCM_SYNTAX ("set!", expand_set_x);
160
161 /* Convenient syntax during boot, expands to primitive syntax. Replaced after
162 psyntax boots. */
163 SCM_SYNTAX ("and", expand_and);
164 SCM_SYNTAX ("cond", expand_cond);
165 SCM_SYNTAX ("letrec", expand_letrec);
166 SCM_SYNTAX ("letrec*", expand_letrec_star);
167 SCM_SYNTAX ("let*", expand_letstar);
168 SCM_SYNTAX ("or", expand_or);
169 SCM_SYNTAX ("lambda*", expand_lambda_star);
170 SCM_SYNTAX ("case-lambda", expand_case_lambda);
171 SCM_SYNTAX ("case-lambda*", expand_case_lambda_star);
172
173
174 SCM_GLOBAL_SYMBOL (scm_sym_apply, "apply");
175 SCM_GLOBAL_SYMBOL (scm_sym_arrow, "=>");
176 SCM_GLOBAL_SYMBOL (scm_sym_at, "@");
177 SCM_GLOBAL_SYMBOL (scm_sym_atat, "@@");
178 SCM_GLOBAL_SYMBOL (scm_sym_at_call_with_values, "@call-with-values");
179 SCM_GLOBAL_SYMBOL (scm_sym_atapply, "@apply");
180 SCM_GLOBAL_SYMBOL (scm_sym_atcall_cc, "@call-with-current-continuation");
181 SCM_GLOBAL_SYMBOL (scm_sym_begin, "begin");
182 SCM_GLOBAL_SYMBOL (scm_sym_case, "case");
183 SCM_GLOBAL_SYMBOL (scm_sym_cond, "cond");
184 SCM_GLOBAL_SYMBOL (scm_sym_define, "define");
185 SCM_GLOBAL_SYMBOL (scm_sym_at_dynamic_wind, "@dynamic-wind");
186 SCM_GLOBAL_SYMBOL (scm_sym_with_fluids, "with-fluids");
187 SCM_GLOBAL_SYMBOL (scm_sym_else, "else");
188 SCM_GLOBAL_SYMBOL (scm_sym_eval_when, "eval-when");
189 SCM_GLOBAL_SYMBOL (scm_sym_if, "if");
190 SCM_GLOBAL_SYMBOL (scm_sym_lambda, "lambda");
191 SCM_GLOBAL_SYMBOL (scm_sym_let, "let");
192 SCM_GLOBAL_SYMBOL (scm_sym_letrec, "letrec");
193 SCM_GLOBAL_SYMBOL (scm_sym_letstar, "let*");
194 SCM_GLOBAL_SYMBOL (scm_sym_or, "or");
195 SCM_GLOBAL_SYMBOL (scm_sym_at_prompt, "@prompt");
196 SCM_GLOBAL_SYMBOL (scm_sym_quote, "quote");
197 SCM_GLOBAL_SYMBOL (scm_sym_set_x, "set!");
198 SCM_SYMBOL (sym_lambda_star, "lambda*");
199 SCM_SYMBOL (sym_eval, "eval");
200 SCM_SYMBOL (sym_load, "load");
201
202 SCM_GLOBAL_SYMBOL (scm_sym_unquote, "unquote");
203 SCM_GLOBAL_SYMBOL (scm_sym_quasiquote, "quasiquote");
204 SCM_GLOBAL_SYMBOL (scm_sym_uq_splicing, "unquote-splicing");
205
206 SCM_KEYWORD (kw_allow_other_keys, "allow-other-keys");
207 SCM_KEYWORD (kw_optional, "optional");
208 SCM_KEYWORD (kw_key, "key");
209 SCM_KEYWORD (kw_rest, "rest");
210
211
212 \f
213
214
215 /* Signal a syntax error. We distinguish between the form that caused the
216 * error and the enclosing expression. The error message will print out as
217 * shown in the following pattern. The file name and line number are only
218 * given when they can be determined from the erroneous form or from the
219 * enclosing expression.
220 *
221 * <filename>: In procedure memoization:
222 * <filename>: In file <name>, line <nr>: <error-message> in <expression>. */
223
224 static void
225 syntax_error (const char* const msg, const SCM form, const SCM expr)
226 {
227 SCM msg_string = scm_from_locale_string (msg);
228 SCM filename = SCM_BOOL_F;
229 SCM linenr = SCM_BOOL_F;
230 const char *format;
231 SCM args;
232
233 if (scm_is_pair (form))
234 {
235 filename = scm_source_property (form, scm_sym_filename);
236 linenr = scm_source_property (form, scm_sym_line);
237 }
238
239 if (scm_is_false (filename) && scm_is_false (linenr) && scm_is_pair (expr))
240 {
241 filename = scm_source_property (expr, scm_sym_filename);
242 linenr = scm_source_property (expr, scm_sym_line);
243 }
244
245 if (!SCM_UNBNDP (expr))
246 {
247 if (scm_is_true (filename))
248 {
249 format = "In file ~S, line ~S: ~A ~S in expression ~S.";
250 args = scm_list_5 (filename, linenr, msg_string, form, expr);
251 }
252 else if (scm_is_true (linenr))
253 {
254 format = "In line ~S: ~A ~S in expression ~S.";
255 args = scm_list_4 (linenr, msg_string, form, expr);
256 }
257 else
258 {
259 format = "~A ~S in expression ~S.";
260 args = scm_list_3 (msg_string, form, expr);
261 }
262 }
263 else
264 {
265 if (scm_is_true (filename))
266 {
267 format = "In file ~S, line ~S: ~A ~S.";
268 args = scm_list_4 (filename, linenr, msg_string, form);
269 }
270 else if (scm_is_true (linenr))
271 {
272 format = "In line ~S: ~A ~S.";
273 args = scm_list_3 (linenr, msg_string, form);
274 }
275 else
276 {
277 format = "~A ~S.";
278 args = scm_list_2 (msg_string, form);
279 }
280 }
281
282 scm_error (syntax_error_key, "memoization", format, args, SCM_BOOL_F);
283 }
284
285
286 \f
287
288
289 static int
290 expand_env_var_is_free (SCM env, SCM x)
291 {
292 for (; scm_is_pair (env); env = CDR (env))
293 if (scm_is_eq (x, CAAR (env)))
294 return 0; /* bound */
295 return 1; /* free */
296 }
297
298 static SCM
299 expand_env_ref_macro (SCM env, SCM x)
300 {
301 SCM var;
302 if (!expand_env_var_is_free (env, x))
303 return SCM_BOOL_F; /* lexical */
304
305 var = scm_module_variable (scm_current_module (), x);
306 if (scm_is_true (var) && scm_is_true (scm_variable_bound_p (var))
307 && scm_is_true (scm_macro_p (scm_variable_ref (var))))
308 return scm_variable_ref (var);
309 else
310 return SCM_BOOL_F; /* anything else */
311 }
312
313 static SCM
314 expand_env_lexical_gensym (SCM env, SCM name)
315 {
316 for (; scm_is_pair (env); env = CDR (env))
317 if (scm_is_eq (name, CAAR (env)))
318 return CDAR (env); /* bound */
319 return SCM_BOOL_F; /* free */
320 }
321
322 static SCM
323 expand_env_extend (SCM env, SCM names, SCM vars)
324 {
325 while (scm_is_pair (names))
326 {
327 env = scm_acons (CAR (names), CAR (vars), env);
328 names = CDR (names);
329 vars = CDR (vars);
330 }
331 return env;
332 }
333
334 static SCM
335 expand (SCM exp, SCM env)
336 {
337 if (scm_is_pair (exp))
338 {
339 SCM car;
340 scm_t_macro_primitive trans = NULL;
341 SCM macro = SCM_BOOL_F;
342
343 car = CAR (exp);
344 if (scm_is_symbol (car))
345 macro = expand_env_ref_macro (env, car);
346
347 if (scm_is_true (macro))
348 trans = scm_i_macro_primitive (macro);
349
350 if (trans)
351 return trans (exp, env);
352 else
353 {
354 SCM arg_exps = SCM_EOL;
355 SCM args = SCM_EOL;
356 SCM proc = CAR (exp);
357
358 for (arg_exps = CDR (exp); scm_is_pair (arg_exps);
359 arg_exps = CDR (arg_exps))
360 args = scm_cons (expand (CAR (arg_exps), env), args);
361 if (scm_is_null (arg_exps))
362 return APPLICATION (scm_source_properties (exp),
363 expand (proc, env),
364 scm_reverse_x (args, SCM_UNDEFINED));
365 else
366 syntax_error ("expected a proper list", exp, SCM_UNDEFINED);
367 }
368 }
369 else if (scm_is_symbol (exp))
370 {
371 SCM gensym = expand_env_lexical_gensym (env, exp);
372 if (scm_is_true (gensym))
373 return LEXICAL_REF (SCM_BOOL_F, exp, gensym);
374 else
375 return TOPLEVEL_REF (SCM_BOOL_F, exp);
376 }
377 else
378 return CONST (SCM_BOOL_F, exp);
379 }
380
381 static SCM
382 expand_exprs (SCM forms, const SCM env)
383 {
384 SCM ret = SCM_EOL;
385
386 for (; !scm_is_null (forms); forms = CDR (forms))
387 ret = scm_cons (expand (CAR (forms), env), ret);
388 return scm_reverse_x (ret, SCM_UNDEFINED);
389 }
390
391 static SCM
392 expand_sequence (const SCM forms, const SCM env)
393 {
394 ASSERT_SYNTAX (scm_ilength (forms) >= 1, s_bad_expression,
395 scm_cons (scm_sym_begin, forms));
396 if (scm_is_null (CDR (forms)))
397 return expand (CAR (forms), env);
398 else
399 return SEQUENCE (SCM_BOOL_F, expand_exprs (forms, env));
400 }
401
402
403 \f
404
405
406 static SCM
407 expand_at (SCM expr, SCM env SCM_UNUSED)
408 {
409 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
410 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
411 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
412
413 return MODULE_REF (scm_source_properties (expr),
414 CADR (expr), CADDR (expr), SCM_BOOL_T);
415 }
416
417 static SCM
418 expand_atat (SCM expr, SCM env SCM_UNUSED)
419 {
420 ASSERT_SYNTAX (scm_ilength (expr) == 3, s_bad_expression, expr);
421 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
422 ASSERT_SYNTAX (scm_is_symbol (CADDR (expr)), s_bad_expression, expr);
423
424 return MODULE_REF (scm_source_properties (expr),
425 CADR (expr), CADDR (expr), SCM_BOOL_F);
426 }
427
428 static SCM
429 expand_and (SCM expr, SCM env)
430 {
431 const SCM cdr_expr = CDR (expr);
432
433 if (scm_is_null (cdr_expr))
434 return CONST (SCM_BOOL_F, SCM_BOOL_T);
435
436 ASSERT_SYNTAX (scm_is_pair (cdr_expr), s_bad_expression, expr);
437
438 if (scm_is_null (CDR (cdr_expr)))
439 return expand (CAR (cdr_expr), env);
440 else
441 return CONDITIONAL (scm_source_properties (expr),
442 expand (CAR (cdr_expr), env),
443 expand_and (cdr_expr, env),
444 CONST (SCM_BOOL_F, SCM_BOOL_F));
445 }
446
447 static SCM
448 expand_begin (SCM expr, SCM env)
449 {
450 const SCM cdr_expr = CDR (expr);
451 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 1, s_bad_expression, expr);
452 return expand_sequence (cdr_expr, env);
453 }
454
455 static SCM
456 expand_cond_clauses (SCM clause, SCM rest, int elp, int alp, SCM env)
457 {
458 SCM test;
459 const long length = scm_ilength (clause);
460 ASSERT_SYNTAX (length >= 1, s_bad_cond_clause, clause);
461
462 test = CAR (clause);
463 if (scm_is_eq (test, scm_sym_else) && elp)
464 {
465 const int last_clause_p = scm_is_null (rest);
466 ASSERT_SYNTAX (length >= 2, s_bad_cond_clause, clause);
467 ASSERT_SYNTAX (last_clause_p, s_misplaced_else_clause, clause);
468 return expand_sequence (CDR (clause), env);
469 }
470
471 if (scm_is_null (rest))
472 rest = VOID (SCM_BOOL_F);
473 else
474 rest = expand_cond_clauses (CAR (rest), CDR (rest), elp, alp, env);
475
476 if (length >= 2
477 && scm_is_eq (CADR (clause), scm_sym_arrow)
478 && alp)
479 {
480 SCM tmp = scm_gensym (scm_from_locale_string ("cond "));
481 SCM new_env = scm_acons (tmp, tmp, env);
482 ASSERT_SYNTAX (length > 2, s_missing_recipient, clause);
483 ASSERT_SYNTAX (length == 3, s_extra_expression, clause);
484 return LET (SCM_BOOL_F,
485 scm_list_1 (tmp),
486 scm_list_1 (tmp),
487 scm_list_1 (expand (test, env)),
488 CONDITIONAL (SCM_BOOL_F,
489 LEXICAL_REF (SCM_BOOL_F, tmp, tmp),
490 APPLICATION (SCM_BOOL_F,
491 expand (CADDR (clause), new_env),
492 scm_list_1 (LEXICAL_REF (SCM_BOOL_F,
493 tmp, tmp))),
494 rest));
495 }
496 /* FIXME length == 1 case */
497 else
498 return CONDITIONAL (SCM_BOOL_F,
499 expand (test, env),
500 expand_sequence (CDR (clause), env),
501 rest);
502 }
503
504 static SCM
505 expand_cond (SCM expr, SCM env)
506 {
507 const int else_literal_p = expand_env_var_is_free (env, scm_sym_else);
508 const int arrow_literal_p = expand_env_var_is_free (env, scm_sym_arrow);
509 const SCM clauses = CDR (expr);
510
511 ASSERT_SYNTAX (scm_ilength (clauses) >= 0, s_bad_expression, expr);
512 ASSERT_SYNTAX (scm_ilength (clauses) >= 1, s_missing_clauses, expr);
513
514 return expand_cond_clauses (CAR (clauses), CDR (clauses),
515 else_literal_p, arrow_literal_p, env);
516 }
517
518 /* lone forward decl */
519 static SCM expand_lambda (SCM expr, SCM env);
520
521 /* According to Section 5.2.1 of R5RS we first have to make sure that the
522 variable is bound, and then perform the `(set! variable expression)'
523 operation. However, EXPRESSION _can_ be evaluated before VARIABLE is
524 bound. This means that EXPRESSION won't necessarily be able to assign
525 values to VARIABLE as in `(define foo (begin (set! foo 1) (+ foo 1)))'. */
526 static SCM
527 expand_define (SCM expr, SCM env)
528 {
529 const SCM cdr_expr = CDR (expr);
530 SCM body;
531 SCM variable;
532
533 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
534 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
535 ASSERT_SYNTAX (!scm_is_pair (env), s_bad_define, expr);
536
537 body = CDR (cdr_expr);
538 variable = CAR (cdr_expr);
539
540 if (scm_is_pair (variable))
541 {
542 ASSERT_SYNTAX_2 (scm_is_symbol (CAR (variable)), s_bad_variable, variable, expr);
543 return TOPLEVEL_DEFINE
544 (scm_source_properties (expr),
545 CAR (variable),
546 expand_lambda (scm_cons (scm_sym_lambda, scm_cons (CDR (variable), body)),
547 env));
548 }
549 ASSERT_SYNTAX_2 (scm_is_symbol (variable), s_bad_variable, variable, expr);
550 ASSERT_SYNTAX (scm_ilength (body) == 1, s_expression, expr);
551 return TOPLEVEL_DEFINE (scm_source_properties (expr), variable,
552 expand (CAR (body), env));
553 }
554
555 static SCM
556 expand_with_fluids (SCM expr, SCM env)
557 {
558 SCM binds, fluids, vals;
559 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
560 binds = CADR (expr);
561 ASSERT_SYNTAX_2 (scm_ilength (binds) >= 0, s_bad_bindings, binds, expr);
562 for (fluids = SCM_EOL, vals = SCM_EOL;
563 scm_is_pair (binds);
564 binds = CDR (binds))
565 {
566 SCM binding = CAR (binds);
567 ASSERT_SYNTAX_2 (scm_ilength (CAR (binds)) == 2, s_bad_binding,
568 binding, expr);
569 fluids = scm_cons (expand (CAR (binding), env), fluids);
570 vals = scm_cons (expand (CADR (binding), env), vals);
571 }
572
573 return DYNLET (scm_source_properties (expr),
574 scm_reverse_x (fluids, SCM_UNDEFINED),
575 scm_reverse_x (vals, SCM_UNDEFINED),
576 expand_sequence (CDDR (expr), env));
577 }
578
579 static SCM
580 expand_eval_when (SCM expr, SCM env)
581 {
582 ASSERT_SYNTAX (scm_ilength (expr) >= 3, s_bad_expression, expr);
583 ASSERT_SYNTAX (scm_ilength (CADR (expr)) > 0, s_bad_expression, expr);
584
585 if (scm_is_true (scm_memq (sym_eval, CADR (expr)))
586 || scm_is_true (scm_memq (sym_load, CADR (expr))))
587 return expand_sequence (CDDR (expr), env);
588 else
589 return VOID (scm_source_properties (expr));
590 }
591
592 static SCM
593 expand_if (SCM expr, SCM env SCM_UNUSED)
594 {
595 const SCM cdr_expr = CDR (expr);
596 const long length = scm_ilength (cdr_expr);
597 ASSERT_SYNTAX (length == 2 || length == 3, s_expression, expr);
598 return CONDITIONAL (scm_source_properties (expr),
599 expand (CADR (expr), env),
600 expand (CADDR (expr), env),
601 ((length == 3)
602 ? expand (CADDDR (expr), env)
603 : VOID (SCM_BOOL_F)));
604 }
605
606 /* A helper function for expand_lambda to support checking for duplicate
607 * formal arguments: Return true if OBJ is `eq?' to one of the elements of
608 * LIST or to the CDR of the last cons. Therefore, LIST may have any of the
609 * forms that a formal argument can have:
610 * <rest>, (<arg1> ...), (<arg1> ... . <rest>) */
611 static int
612 c_improper_memq (SCM obj, SCM list)
613 {
614 for (; scm_is_pair (list); list = CDR (list))
615 {
616 if (scm_is_eq (CAR (list), obj))
617 return 1;
618 }
619 return scm_is_eq (list, obj);
620 }
621
622 static SCM
623 expand_lambda_case (SCM clause, SCM alternate, SCM env)
624 {
625 SCM formals;
626 SCM rest;
627 SCM req = SCM_EOL;
628 SCM vars = SCM_EOL;
629 SCM body;
630 int nreq = 0;
631
632 ASSERT_SYNTAX (scm_is_pair (clause) && scm_is_pair (CDR (clause)),
633 s_bad_expression, scm_cons (scm_sym_lambda, clause));
634
635 /* Before iterating the list of formal arguments, make sure the formals
636 * actually are given as either a symbol or a non-cyclic list. */
637 formals = CAR (clause);
638 if (scm_is_pair (formals))
639 {
640 /* Dirk:FIXME:: We should check for a cyclic list of formals, and if
641 * detected, report a 'Bad formals' error. */
642 }
643 else
644 ASSERT_SYNTAX_2 (scm_is_symbol (formals) || scm_is_null (formals),
645 s_bad_formals, formals, scm_cons (scm_sym_lambda, clause));
646
647 /* Now iterate the list of formal arguments to check if all formals are
648 * symbols, and that there are no duplicates. */
649 while (scm_is_pair (formals))
650 {
651 const SCM formal = CAR (formals);
652 formals = CDR (formals);
653 ASSERT_SYNTAX_2 (scm_is_symbol (formal), s_bad_formal, formal,
654 scm_cons (scm_sym_lambda, clause));
655 ASSERT_SYNTAX_2 (!c_improper_memq (formal, formals), s_duplicate_formal,
656 formal, scm_cons (scm_sym_lambda, clause));
657 nreq++;
658 req = scm_cons (formal, req);
659 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
660 env = scm_acons (formal, CAR (vars), env);
661 }
662
663 ASSERT_SYNTAX_2 (scm_is_null (formals) || scm_is_symbol (formals),
664 s_bad_formal, formals, scm_cons (scm_sym_lambda, clause));
665 if (scm_is_symbol (formals))
666 {
667 rest = formals;
668 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
669 env = scm_acons (rest, CAR (vars), env);
670 }
671 else
672 rest = SCM_BOOL_F;
673
674 body = expand_sequence (CDR (clause), env);
675 req = scm_reverse_x (req, SCM_UNDEFINED);
676 vars = scm_reverse_x (vars, SCM_UNDEFINED);
677
678 if (scm_is_true (alternate) && !(SCM_EXPANDED_P (alternate) && SCM_EXPANDED_TYPE (alternate) == SCM_EXPANDED_LAMBDA_CASE))
679 abort ();
680
681 return LAMBDA_CASE (SCM_BOOL_F, req, SCM_BOOL_F, rest, SCM_BOOL_F,
682 SCM_EOL, vars, body, alternate);
683 }
684
685 static SCM
686 expand_lambda (SCM expr, SCM env)
687 {
688 return LAMBDA (scm_source_properties (expr),
689 SCM_EOL,
690 expand_lambda_case (CDR (expr), SCM_BOOL_F, env));
691 }
692
693 static SCM
694 expand_lambda_star_case (SCM clause, SCM alternate, SCM env)
695 {
696 SCM req, opt, kw, allow_other_keys, rest, formals, vars, body, tmp;
697 SCM inits;
698 int nreq, nopt;
699
700 const long length = scm_ilength (clause);
701 ASSERT_SYNTAX (length >= 1, s_bad_expression,
702 scm_cons (sym_lambda_star, clause));
703 ASSERT_SYNTAX (length >= 2, s_missing_expression,
704 scm_cons (sym_lambda_star, clause));
705
706 formals = CAR (clause);
707 body = CDR (clause);
708
709 nreq = nopt = 0;
710 req = opt = kw = SCM_EOL;
711 rest = allow_other_keys = SCM_BOOL_F;
712
713 while (scm_is_pair (formals) && scm_is_symbol (CAR (formals)))
714 {
715 nreq++;
716 req = scm_cons (CAR (formals), req);
717 formals = scm_cdr (formals);
718 }
719
720 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_optional))
721 {
722 formals = CDR (formals);
723 while (scm_is_pair (formals)
724 && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals))))
725 {
726 nopt++;
727 opt = scm_cons (CAR (formals), opt);
728 formals = scm_cdr (formals);
729 }
730 }
731
732 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_key))
733 {
734 formals = CDR (formals);
735 while (scm_is_pair (formals)
736 && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals))))
737 {
738 kw = scm_cons (CAR (formals), kw);
739 formals = scm_cdr (formals);
740 }
741 }
742
743 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_allow_other_keys))
744 {
745 formals = CDR (formals);
746 allow_other_keys = SCM_BOOL_T;
747 }
748
749 if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_rest))
750 {
751 ASSERT_SYNTAX (scm_ilength (formals) == 2, s_bad_formals,
752 CAR (clause));
753 rest = CADR (formals);
754 }
755 else if (scm_is_symbol (formals))
756 rest = formals;
757 else
758 {
759 ASSERT_SYNTAX (scm_is_null (formals), s_bad_formals, CAR (clause));
760 rest = SCM_BOOL_F;
761 }
762
763 /* Now, iterate through them a second time, building up an expansion-time
764 environment, checking, expanding and canonicalizing the opt/kw init forms,
765 and eventually memoizing the body as well. Note that the rest argument, if
766 any, is expanded before keyword args, thus necessitating the second
767 pass.
768
769 Also note that the specific environment during expansion of init
770 expressions here needs to coincide with the environment when psyntax
771 expands. A lot of effort for something that is only used in the bootstrap
772 expandr, you say? Yes. Yes it is.
773 */
774
775 vars = SCM_EOL;
776 req = scm_reverse_x (req, SCM_EOL);
777 for (tmp = req; scm_is_pair (tmp); tmp = scm_cdr (tmp))
778 {
779 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
780 env = scm_acons (CAR (tmp), CAR (vars), env);
781 }
782
783 /* Build up opt inits and env */
784 inits = SCM_EOL;
785 opt = scm_reverse_x (opt, SCM_EOL);
786 for (tmp = opt; scm_is_pair (tmp); tmp = scm_cdr (tmp))
787 {
788 SCM x = CAR (tmp);
789 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
790 env = scm_acons (x, CAR (vars), env);
791 if (scm_is_symbol (x))
792 inits = scm_cons (CONST (SCM_BOOL_F, SCM_BOOL_F), inits);
793 else
794 {
795 ASSERT_SYNTAX (scm_ilength (x) == 2 && scm_is_symbol (CAR (x)),
796 s_bad_formals, CAR (clause));
797 inits = scm_cons (expand (CADR (x), env), inits);
798 }
799 env = scm_acons (scm_is_symbol (x) ? x : CAR (x), CAR (vars), env);
800 }
801 if (scm_is_null (opt))
802 opt = SCM_BOOL_F;
803
804 /* Process rest before keyword args */
805 if (scm_is_true (rest))
806 {
807 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
808 env = scm_acons (rest, CAR (vars), env);
809 }
810
811 /* Build up kw inits, env, and kw-canon list */
812 if (scm_is_null (kw))
813 kw = SCM_BOOL_F;
814 else
815 {
816 SCM kw_canon = SCM_EOL;
817 kw = scm_reverse_x (kw, SCM_UNDEFINED);
818 for (tmp = kw; scm_is_pair (tmp); tmp = scm_cdr (tmp))
819 {
820 SCM x, sym, k, init;
821 x = CAR (tmp);
822 if (scm_is_symbol (x))
823 {
824 sym = x;
825 init = SCM_BOOL_F;
826 k = scm_symbol_to_keyword (sym);
827 }
828 else if (scm_ilength (x) == 2 && scm_is_symbol (CAR (x)))
829 {
830 sym = CAR (x);
831 init = CADR (x);
832 k = scm_symbol_to_keyword (sym);
833 }
834 else if (scm_ilength (x) == 3 && scm_is_symbol (CAR (x))
835 && scm_is_keyword (CADDR (x)))
836 {
837 sym = CAR (x);
838 init = CADR (x);
839 k = CADDR (x);
840 }
841 else
842 syntax_error (s_bad_formals, CAR (clause), SCM_UNDEFINED);
843
844 inits = scm_cons (expand (init, env), inits);
845 vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars);
846 kw_canon = scm_cons (scm_list_3 (k, sym, CAR (vars)), kw_canon);
847 env = scm_acons (sym, CAR (vars), env);
848 }
849 kw_canon = scm_reverse_x (kw_canon, SCM_UNDEFINED);
850 kw = scm_cons (allow_other_keys, kw_canon);
851 }
852
853 /* We should check for no duplicates, but given that psyntax does this
854 already, we can punt on it here... */
855
856 vars = scm_reverse_x (vars, SCM_UNDEFINED);
857 inits = scm_reverse_x (inits, SCM_UNDEFINED);
858 body = expand_sequence (body, env);
859
860 return LAMBDA_CASE (SCM_BOOL_F, req, opt, rest, kw, inits, vars, body,
861 alternate);
862 }
863
864 static SCM
865 expand_lambda_star (SCM expr, SCM env)
866 {
867 return LAMBDA (scm_source_properties (expr),
868 SCM_EOL,
869 expand_lambda_star_case (CDR (expr), SCM_BOOL_F, env));
870 }
871
872 static SCM
873 expand_case_lambda_clauses (SCM expr, SCM rest, SCM env)
874 {
875 SCM alt;
876
877 if (scm_is_pair (rest))
878 alt = expand_case_lambda_clauses (CAR (rest), CDR (rest), env);
879 else
880 alt = SCM_BOOL_F;
881
882 return expand_lambda_case (expr, alt, env);
883 }
884
885 static SCM
886 expand_case_lambda (SCM expr, SCM env)
887 {
888 ASSERT_SYNTAX (scm_is_pair (CDR (expr)), s_missing_expression, expr);
889
890 return LAMBDA (scm_source_properties (expr),
891 SCM_EOL,
892 expand_case_lambda_clauses (CADR (expr), CDDR (expr), env));
893 }
894
895 static SCM
896 expand_case_lambda_star_clauses (SCM expr, SCM rest, SCM env)
897 {
898 SCM alt;
899
900 if (scm_is_pair (rest))
901 alt = expand_case_lambda_star_clauses (CAR (rest), CDR (rest), env);
902 else
903 alt = SCM_BOOL_F;
904
905 return expand_lambda_star_case (expr, alt, env);
906 }
907
908 static SCM
909 expand_case_lambda_star (SCM expr, SCM env)
910 {
911 ASSERT_SYNTAX (scm_is_pair (CDR (expr)), s_missing_expression, expr);
912
913 return LAMBDA (scm_source_properties (expr),
914 SCM_EOL,
915 expand_case_lambda_star_clauses (CADR (expr), CDDR (expr), env));
916 }
917
918 /* Check if the format of the bindings is ((<symbol> <init-form>) ...). */
919 static void
920 check_bindings (const SCM bindings, const SCM expr)
921 {
922 SCM binding_idx;
923
924 ASSERT_SYNTAX_2 (scm_ilength (bindings) >= 0,
925 s_bad_bindings, bindings, expr);
926
927 binding_idx = bindings;
928 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
929 {
930 SCM name; /* const */
931
932 const SCM binding = CAR (binding_idx);
933 ASSERT_SYNTAX_2 (scm_ilength (binding) == 2,
934 s_bad_binding, binding, expr);
935
936 name = CAR (binding);
937 ASSERT_SYNTAX_2 (scm_is_symbol (name), s_bad_variable, name, expr);
938 }
939 }
940
941 /* The bindings, which must have the format ((v1 i1) (v2 i2) ... (vn in)), are
942 * transformed to the lists (vn .. v2 v1) and (i1 i2 ... in). If a duplicate
943 * variable name is detected, an error is signalled. */
944 static void
945 transform_bindings (const SCM bindings, const SCM expr,
946 SCM *const names, SCM *const vars, SCM *const initptr)
947 {
948 SCM rnames = SCM_EOL;
949 SCM rvars = SCM_EOL;
950 SCM rinits = SCM_EOL;
951 SCM binding_idx = bindings;
952 for (; !scm_is_null (binding_idx); binding_idx = CDR (binding_idx))
953 {
954 const SCM binding = CAR (binding_idx);
955 const SCM CDR_binding = CDR (binding);
956 const SCM name = CAR (binding);
957 ASSERT_SYNTAX_2 (scm_is_false (scm_c_memq (name, rnames)),
958 s_duplicate_binding, name, expr);
959 rnames = scm_cons (name, rnames);
960 rvars = scm_cons (scm_gensym (SCM_UNDEFINED), rvars);
961 rinits = scm_cons (CAR (CDR_binding), rinits);
962 }
963 *names = scm_reverse_x (rnames, SCM_UNDEFINED);
964 *vars = scm_reverse_x (rvars, SCM_UNDEFINED);
965 *initptr = scm_reverse_x (rinits, SCM_UNDEFINED);
966 }
967
968 /* FIXME: Remove named let in this boot expander. */
969 static SCM
970 expand_named_let (const SCM expr, SCM env)
971 {
972 SCM var_names, var_syms, inits;
973 SCM inner_env;
974 SCM name_sym;
975
976 const SCM cdr_expr = CDR (expr);
977 const SCM name = CAR (cdr_expr);
978 const SCM cddr_expr = CDR (cdr_expr);
979 const SCM bindings = CAR (cddr_expr);
980 check_bindings (bindings, expr);
981
982 transform_bindings (bindings, expr, &var_names, &var_syms, &inits);
983 name_sym = scm_gensym (SCM_UNDEFINED);
984 inner_env = scm_acons (name, name_sym, env);
985 inner_env = expand_env_extend (inner_env, var_names, var_syms);
986
987 return LETREC
988 (scm_source_properties (expr), SCM_BOOL_F,
989 scm_list_1 (name), scm_list_1 (name_sym),
990 scm_list_1 (LAMBDA (SCM_BOOL_F,
991 SCM_EOL,
992 LAMBDA_CASE (SCM_BOOL_F, var_names, SCM_BOOL_F, SCM_BOOL_F,
993 SCM_BOOL_F, SCM_BOOL_F, var_syms,
994 expand_sequence (CDDDR (expr), inner_env),
995 SCM_BOOL_F))),
996 APPLICATION (SCM_BOOL_F,
997 LEXICAL_REF (SCM_BOOL_F, name, name_sym),
998 expand_exprs (inits, env)));
999 }
1000
1001 static SCM
1002 expand_let (SCM expr, SCM env)
1003 {
1004 SCM bindings;
1005
1006 const SCM cdr_expr = CDR (expr);
1007 const long length = scm_ilength (cdr_expr);
1008 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
1009 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
1010
1011 bindings = CAR (cdr_expr);
1012 if (scm_is_symbol (bindings))
1013 {
1014 ASSERT_SYNTAX (length >= 3, s_missing_expression, expr);
1015 return expand_named_let (expr, env);
1016 }
1017
1018 check_bindings (bindings, expr);
1019 if (scm_is_null (bindings))
1020 return expand_sequence (CDDR (expr), env);
1021 else
1022 {
1023 SCM var_names, var_syms, inits;
1024 transform_bindings (bindings, expr, &var_names, &var_syms, &inits);
1025 return LET (SCM_BOOL_F,
1026 var_names, var_syms, expand_exprs (inits, env),
1027 expand_sequence (CDDR (expr),
1028 expand_env_extend (env, var_names,
1029 var_syms)));
1030 }
1031 }
1032
1033 static SCM
1034 expand_letrec_helper (SCM expr, SCM env, SCM in_order_p)
1035 {
1036 SCM bindings;
1037
1038 const SCM cdr_expr = CDR (expr);
1039 const long length = scm_ilength (cdr_expr);
1040 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
1041 ASSERT_SYNTAX (length >= 2, s_missing_expression, expr);
1042
1043 bindings = CAR (cdr_expr);
1044 check_bindings (bindings, expr);
1045 if (scm_is_null (bindings))
1046 return expand_sequence (CDDR (expr), env);
1047 else
1048 {
1049 SCM var_names, var_syms, inits;
1050 transform_bindings (bindings, expr, &var_names, &var_syms, &inits);
1051 env = expand_env_extend (env, var_names, var_syms);
1052 return LETREC (SCM_BOOL_F, in_order_p,
1053 var_names, var_syms, expand_exprs (inits, env),
1054 expand_sequence (CDDR (expr), env));
1055 }
1056 }
1057
1058 static SCM
1059 expand_letrec (SCM expr, SCM env)
1060 {
1061 return expand_letrec_helper (expr, env, SCM_BOOL_F);
1062 }
1063
1064 static SCM
1065 expand_letrec_star (SCM expr, SCM env)
1066 {
1067 return expand_letrec_helper (expr, env, SCM_BOOL_T);
1068 }
1069
1070 static SCM
1071 expand_letstar_clause (SCM bindings, SCM body, SCM env SCM_UNUSED)
1072 {
1073 if (scm_is_null (bindings))
1074 return expand_sequence (body, env);
1075 else
1076 {
1077 SCM bind, name, sym, init;
1078
1079 ASSERT_SYNTAX (scm_is_pair (bindings), s_bad_expression, bindings);
1080 bind = CAR (bindings);
1081 ASSERT_SYNTAX (scm_ilength (bind) == 2, s_bad_binding, bind);
1082 name = CAR (bind);
1083 sym = scm_gensym (SCM_UNDEFINED);
1084 init = CADR (bind);
1085
1086 return LET (SCM_BOOL_F, scm_list_1 (name), scm_list_1 (sym),
1087 scm_list_1 (expand (init, env)),
1088 expand_letstar_clause (CDR (bindings), body,
1089 scm_acons (name, sym, env)));
1090 }
1091 }
1092
1093 static SCM
1094 expand_letstar (SCM expr, SCM env SCM_UNUSED)
1095 {
1096 const SCM cdr_expr = CDR (expr);
1097 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1098 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 2, s_missing_expression, expr);
1099
1100 return expand_letstar_clause (CADR (expr), CDDR (expr), env);
1101 }
1102
1103 static SCM
1104 expand_or (SCM expr, SCM env SCM_UNUSED)
1105 {
1106 SCM tail = CDR (expr);
1107 const long length = scm_ilength (tail);
1108
1109 ASSERT_SYNTAX (length >= 0, s_bad_expression, expr);
1110
1111 if (scm_is_null (CDR (expr)))
1112 return CONST (SCM_BOOL_F, SCM_BOOL_F);
1113 else
1114 {
1115 SCM tmp = scm_gensym (SCM_UNDEFINED);
1116 return LET (SCM_BOOL_F,
1117 scm_list_1 (tmp), scm_list_1 (tmp),
1118 scm_list_1 (expand (CADR (expr), env)),
1119 CONDITIONAL (SCM_BOOL_F,
1120 LEXICAL_REF (SCM_BOOL_F, tmp, tmp),
1121 LEXICAL_REF (SCM_BOOL_F, tmp, tmp),
1122 expand_or (CDR (expr),
1123 scm_acons (tmp, tmp, env))));
1124 }
1125 }
1126
1127 static SCM
1128 expand_quote (SCM expr, SCM env SCM_UNUSED)
1129 {
1130 SCM quotee;
1131
1132 const SCM cdr_expr = CDR (expr);
1133 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1134 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 1, s_expression, expr);
1135 quotee = CAR (cdr_expr);
1136 return CONST (scm_source_properties (expr), quotee);
1137 }
1138
1139 static SCM
1140 expand_set_x (SCM expr, SCM env)
1141 {
1142 SCM variable;
1143 SCM vmem;
1144
1145 const SCM cdr_expr = CDR (expr);
1146 ASSERT_SYNTAX (scm_ilength (cdr_expr) >= 0, s_bad_expression, expr);
1147 ASSERT_SYNTAX (scm_ilength (cdr_expr) == 2, s_expression, expr);
1148 variable = CAR (cdr_expr);
1149 vmem = expand (variable, env);
1150
1151 switch (SCM_EXPANDED_TYPE (vmem))
1152 {
1153 case SCM_EXPANDED_LEXICAL_REF:
1154 return LEXICAL_SET (scm_source_properties (expr),
1155 SCM_EXPANDED_REF (vmem, LEXICAL_REF, NAME),
1156 SCM_EXPANDED_REF (vmem, LEXICAL_REF, GENSYM),
1157 expand (CADDR (expr), env));
1158 case SCM_EXPANDED_TOPLEVEL_REF:
1159 return TOPLEVEL_SET (scm_source_properties (expr),
1160 SCM_EXPANDED_REF (vmem, TOPLEVEL_REF, NAME),
1161 expand (CADDR (expr), env));
1162 case SCM_EXPANDED_MODULE_REF:
1163 return MODULE_SET (scm_source_properties (expr),
1164 SCM_EXPANDED_REF (vmem, MODULE_REF, MOD),
1165 SCM_EXPANDED_REF (vmem, MODULE_REF, NAME),
1166 SCM_EXPANDED_REF (vmem, MODULE_REF, PUBLIC),
1167 expand (CADDR (expr), env));
1168 default:
1169 syntax_error (s_bad_variable, variable, expr);
1170 }
1171 }
1172
1173
1174 \f
1175
1176 /* This is the boot expander. It is later replaced with psyntax's sc-expand. */
1177 SCM_DEFINE (scm_macroexpand, "macroexpand", 1, 0, 0,
1178 (SCM exp),
1179 "Expand the expression @var{exp}.")
1180 #define FUNC_NAME s_scm_macroexpand
1181 {
1182 return expand (exp, scm_current_module ());
1183 }
1184 #undef FUNC_NAME
1185
1186 SCM_DEFINE (scm_macroexpanded_p, "macroexpanded?", 1, 0, 0,
1187 (SCM exp),
1188 "Return @code{#t} if @var{exp} is an expanded expression.")
1189 #define FUNC_NAME s_scm_macroexpanded_p
1190 {
1191 return scm_from_bool (SCM_EXPANDED_P (exp));
1192 }
1193 #undef FUNC_NAME
1194
1195
1196 \f
1197
1198 #define DEFINE_NAMES(type) \
1199 { \
1200 static const char *fields[] = SCM_EXPANDED_##type##_FIELD_NAMES; \
1201 exp_field_names[SCM_EXPANDED_##type] = fields; \
1202 exp_names[SCM_EXPANDED_##type] = SCM_EXPANDED_##type##_TYPE_NAME; \
1203 exp_nfields[SCM_EXPANDED_##type] = SCM_NUM_EXPANDED_##type##_FIELDS; \
1204 }
1205
1206 static SCM
1207 make_exp_vtable (size_t n)
1208 {
1209 SCM layout, printer, name, code, fields;
1210
1211 layout = scm_string_to_symbol
1212 (scm_string_append (scm_make_list (scm_from_size_t (exp_nfields[n]),
1213 scm_from_locale_string ("pw"))));
1214 printer = SCM_BOOL_F;
1215 name = scm_from_locale_symbol (exp_names[n]);
1216 code = scm_from_size_t (n);
1217 fields = SCM_EOL;
1218 {
1219 size_t m = exp_nfields[n];
1220 while (m--)
1221 fields = scm_cons (scm_from_locale_symbol (exp_field_names[n][m]), fields);
1222 }
1223
1224 return scm_c_make_struct (scm_exp_vtable_vtable, 0, 5,
1225 SCM_UNPACK (layout), SCM_UNPACK (printer), SCM_UNPACK (name),
1226 SCM_UNPACK (code), SCM_UNPACK (fields));
1227 }
1228
1229 void
1230 scm_init_expand ()
1231 {
1232 size_t n;
1233 SCM exp_vtable_list = SCM_EOL;
1234
1235 DEFINE_NAMES (VOID);
1236 DEFINE_NAMES (CONST);
1237 DEFINE_NAMES (PRIMITIVE_REF);
1238 DEFINE_NAMES (LEXICAL_REF);
1239 DEFINE_NAMES (LEXICAL_SET);
1240 DEFINE_NAMES (MODULE_REF);
1241 DEFINE_NAMES (MODULE_SET);
1242 DEFINE_NAMES (TOPLEVEL_REF);
1243 DEFINE_NAMES (TOPLEVEL_SET);
1244 DEFINE_NAMES (TOPLEVEL_DEFINE);
1245 DEFINE_NAMES (CONDITIONAL);
1246 DEFINE_NAMES (APPLICATION);
1247 DEFINE_NAMES (SEQUENCE);
1248 DEFINE_NAMES (LAMBDA);
1249 DEFINE_NAMES (LAMBDA_CASE);
1250 DEFINE_NAMES (LET);
1251 DEFINE_NAMES (LETREC);
1252 DEFINE_NAMES (DYNLET);
1253
1254 scm_exp_vtable_vtable =
1255 scm_make_vtable (scm_from_locale_string (SCM_VTABLE_BASE_LAYOUT "pwuwpw"),
1256 SCM_BOOL_F);
1257
1258 for (n = 0; n < SCM_NUM_EXPANDED_TYPES; n++)
1259 exp_vtables[n] = make_exp_vtable (n);
1260
1261 /* Now walk back down, consing in reverse. */
1262 while (n--)
1263 exp_vtable_list = scm_cons (exp_vtables[n], exp_vtable_list);
1264
1265 scm_c_define ("%expanded-vtables", scm_vector (exp_vtable_list));
1266
1267 #include "libguile/expand.x"
1268 }
1269
1270 /*
1271 Local Variables:
1272 c-file-style: "gnu"
1273 End:
1274 */