mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-27 15:02:12 -08:00
181 lines
4.1 KiB
D
181 lines
4.1 KiB
D
/*
|
|
macros.c -- Macros.
|
|
*/
|
|
/*
|
|
Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
|
|
Copyright (c) 1990, Giuseppe Attardi.
|
|
Copyright (c) 2001, Juan Jose Garcia Ripoll.
|
|
|
|
ECL is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
See file '../Copyright' for full details.
|
|
*/
|
|
|
|
#include "ecl.h"
|
|
#include "internal.h"
|
|
|
|
/******************************* REQUIRES ******************************/
|
|
|
|
/* Requires expand-defmacro, from lsp/defmacro.lsp */
|
|
|
|
/******************************* ------- ******************************/
|
|
|
|
/*
|
|
MACRO_DEF is an internal function which, given a form, returns
|
|
the expansion function if the form is a macro form. Otherwise,
|
|
MACRO_DEF returns NIL.
|
|
*/
|
|
static cl_object
|
|
search_symbol_macro(cl_object name, cl_object env)
|
|
{
|
|
cl_object record = assq(name, CAR(env));
|
|
if (Null(record))
|
|
return si_get_sysprop(name, @'si::symbol-macro');
|
|
else if (CADR(record) == @'si::symbol-macro')
|
|
return CADDR(record);
|
|
else
|
|
return Cnil;
|
|
}
|
|
|
|
cl_object
|
|
search_macro(cl_object name, cl_object env)
|
|
{
|
|
cl_object record = assq(name, CDR(env));
|
|
if (CONSP(record) && CADR(record) == @'si::macro')
|
|
return CADDR(record);
|
|
return Cnil;
|
|
}
|
|
|
|
static cl_object
|
|
macro_def(cl_object form, cl_object env)
|
|
{
|
|
cl_object head, fd;
|
|
|
|
if (ATOM(form)) {
|
|
if (!SYMBOLP(form))
|
|
return Cnil;
|
|
/* First look for SYMBOL-MACROLET definitions */
|
|
fd = search_symbol_macro(form, env);
|
|
return fd;
|
|
}
|
|
head = CAR(form);
|
|
if (!SYMBOLP(head))
|
|
return(Cnil);
|
|
fd = search_macro(head, env);
|
|
if (!Null(fd))
|
|
return fd;
|
|
else if (head->symbol.mflag)
|
|
return(SYM_FUN(head));
|
|
else
|
|
return(Cnil);
|
|
}
|
|
|
|
@(defun macroexpand (form &optional (env Cnil))
|
|
cl_object new_form = OBJNULL;
|
|
cl_object done = Cnil;
|
|
@
|
|
new_form = macro_expand1(form, env);
|
|
while (new_form != form) {
|
|
done = Ct;
|
|
form = new_form;
|
|
new_form = macro_expand(form, env);
|
|
}
|
|
@(return new_form done)
|
|
@)
|
|
|
|
@(defun macroexpand_1 (form &optional (env Cnil))
|
|
cl_object new_form;
|
|
@
|
|
new_form = macro_expand1(form, env);
|
|
@(return new_form (new_form == form? Cnil : Ct))
|
|
@)
|
|
|
|
/*
|
|
MACRO_EXPAND1 is an internal function which simply applies the
|
|
function EXP_FUN to FORM. On return, the expanded form is stored
|
|
in VALUES(0).
|
|
*/
|
|
cl_object
|
|
macro_expand1(cl_object form, cl_object env)
|
|
{
|
|
cl_object hook, exp_fun;
|
|
|
|
exp_fun = macro_def(form, env);
|
|
if (Null(exp_fun))
|
|
return form;
|
|
hook = symbol_value(@'*macroexpand-hook*');
|
|
if (hook == @'funcall')
|
|
return funcall(3, exp_fun, form, env);
|
|
else
|
|
return funcall(4, hook, exp_fun, form, env);
|
|
}
|
|
|
|
/*
|
|
MACRO_EXPAND expands a form as many times as possible and returns
|
|
the finally expanded form.
|
|
*/
|
|
cl_object
|
|
macro_expand(cl_object form, cl_object env)
|
|
{
|
|
cl_object new_form;
|
|
|
|
for (new_form = OBJNULL; new_form != form; form = new_form) {
|
|
new_form = macro_expand1(form, env);
|
|
}
|
|
return new_form;
|
|
}
|
|
|
|
static cl_object
|
|
or_macro(cl_object whole, cl_object env)
|
|
{
|
|
cl_object output = Cnil;
|
|
whole = CDR(whole);
|
|
if (Null(whole)) /* (OR) => NIL */
|
|
@(return Cnil);
|
|
while (!Null(CDR(whole))) {
|
|
output = CONS(CONS(CAR(whole), Cnil), output);
|
|
whole = CDR(whole);
|
|
}
|
|
if (Null(output)) /* (OR form1) => form1 */
|
|
@(return CAR(whole));
|
|
/* (OR form1 ... formn forml) => (COND (form1) ... (formn) (t forml)) */
|
|
output = CONS(cl_list(2, Ct, CAR(whole)), output);
|
|
@(return CONS(@'cond', cl_nreverse(output)))
|
|
}
|
|
|
|
static cl_object
|
|
expand_and(cl_object whole)
|
|
{
|
|
if (Null(whole))
|
|
return Ct;
|
|
if (Null(CDR(whole)))
|
|
return CAR(whole);
|
|
return cl_list(3, @'if', CAR(whole), expand_and(CDR(whole)));
|
|
}
|
|
|
|
static cl_object
|
|
and_macro(cl_object whole, cl_object env)
|
|
{
|
|
@(return expand_and(CDR(whole)))
|
|
}
|
|
|
|
static cl_object
|
|
when_macro(cl_object whole, cl_object env)
|
|
{
|
|
cl_object args = CDR(whole);
|
|
if (endp(args))
|
|
FEprogram_error("Syntax error: ~S.", 1, whole);
|
|
return cl_list(3, @'if', CAR(args), CONS(@'progn', CDR(args)));
|
|
}
|
|
|
|
void
|
|
init_macros(void)
|
|
{
|
|
ECL_SET(@'*macroexpand-hook*', @'funcall');
|
|
cl_def_c_macro(@'or', or_macro, 2);
|
|
cl_def_c_macro(@'and', and_macro, 2);
|
|
cl_def_c_macro(@'when', when_macro, 2);
|
|
}
|