1
/* macros.c -- macroexpand etc
2
Copyright (C) 1993, 1994, 2000 John Harper <john@dcs.warwick.ac.uk>
3
$Id: macros.c,v 1.11 2001/08/08 06:15:32 jsh Exp $
5
This file is part of librep.
7
librep is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
12
librep is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with librep; see the file COPYING. If not, write to
19
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23
The idea is to memoize macro expansions, but only until the next
24
garbage collection. This introduces very little memory overhead, two
25
cons cells per expansion (the expansion is around anyway until gc)
27
Whether it would be useful to keep expansions around for longer is
28
something that needs to be looked at later..
30
It's actually pretty good on its own. E.g. doing (compile-compiler)
31
with all interpreted code gives a miss ratio of about .023 */
42
#define HIST_HASH_FN(x) (((x) >> 4) % HIST_SIZE)
44
/* Each entry is a chain of cons cells. But note that the last cell's
45
cdr is dotted to ((repv)0) not Qnil */
46
static repv history[HIST_SIZE];
48
static int macro_hits, macro_misses;
50
DEFSYM(macro_environment, "macro-environment");
53
symbol_value_in_structure (repv structure, repv sym)
55
repv old = rep_structure, value;
56
rep_structure = structure;
57
value = Fsymbol_value (sym, Qt);
62
DEFUN("macroexpand-1", Fmacroexpand_1, Smacroexpand_1,
63
(repv form, repv env), rep_Subr2) /*
64
::doc:rep.lang.interpreter#macroexpand-1::
65
macroexpand-1 FORM [ENVIRONMENT]
67
If FORM is a macro call, expand it once and return the resulting form.
69
If ENVIRONMENT is specified it is a function to call to do the actual
70
expansion. Any macro expanders recursively calling macroexpand should
71
pass the value of the `macro-environment' variable to this parameter.
74
rep_GC_root gc_bindings;
77
if (!rep_CONSP (form))
80
if (env != Qnil && Ffunctionp (env) != Qnil)
81
return rep_call_lisp1 (env, form);
87
if (rep_STRUCTUREP (env))
88
/* deref the symbol in the module that it appeared in.. */
89
car = symbol_value_in_structure (env, car);
91
car = Fsymbol_value (car, Qt);
92
if (!rep_CONSP(car) || rep_CAR(car) != Qmacro)
96
else if (rep_CONSP(car) && rep_CAR(car) == Qmacro)
99
if (Ffunctionp(car) == Qnil)
102
if (rep_FUNARGP (car))
104
repv fun = rep_FUNARG (car)->fun;
105
if (rep_CONSP (fun) && rep_CAR (fun) == Qautoload)
107
/* an autoload. handle this locally. */
109
rep_GC_root gc_form, gc_env;
114
rep_USE_FUNARG (car);
115
rep_PUSHGC (gc_form, form);
116
rep_PUSHGC (gc_env, env);
117
car = rep_load_autoload (car);
118
rep_POPGC; rep_POPGC;
128
bindings = rep_bind_symbol (Qnil, Qmacro_environment, rep_structure);
129
rep_PUSHGC(gc_bindings, bindings);
130
form = rep_funcall (car, rep_CDR(form), rep_FALSE);
132
rep_unbind_symbols (bindings);
136
DEFUN("macroexpand", Fmacroexpand, Smacroexpand,
137
(repv form, repv env), rep_Subr2) /*
138
::doc:rep.lang.interpreter#macroexpand::
139
macroexpand FORM [ENVIRONMENT]
141
If FORM is a macro call, expand it until it isn't.
143
If ENVIRONMENT is specified it is a function to call to do the actual
144
expansion. Any macro expanders recursively calling macroexpand should
145
pass the value of the `macro-environment' variable to this parameter.
148
repv input = form, pred, ptr;
149
rep_GC_root gc_input, gc_pred;
151
if (!rep_CONSP (form))
154
/* Search the history */
155
ptr = history[HIST_HASH_FN(form)];
158
if (rep_CAAR (ptr) == form)
161
return rep_CDAR (ptr);
167
rep_PUSHGC(gc_input, input);
168
rep_PUSHGC(gc_pred, pred);
172
form = Fmacroexpand_1 (pred, env);
173
if (form == rep_NULL || form == pred)
177
rep_POPGC; rep_POPGC;
179
if (form != rep_NULL)
181
/* Cache for future use */
182
u_int hash = HIST_HASH_FN(input);
183
history[hash] = Fcons (Fcons (input, form), history[hash]);
190
rep_macros_before_gc (void)
192
/* XXX Perhaps be more discerning? (We would need to arrange some
193
XXX marking then though..) */
194
rep_macros_clear_history ();
198
rep_macros_clear_history (void)
200
memset (history, 0, sizeof (history));
204
rep_macros_init (void)
206
repv tem = rep_push_structure ("rep.lang.interpreter");
207
rep_ADD_SUBR(Smacroexpand);
208
rep_ADD_SUBR(Smacroexpand_1);
209
rep_INTERN_SPECIAL(macro_environment);
210
Fset (Qmacro_environment, Qnil);
211
rep_macros_clear_history ();
212
rep_pop_structure (tem);