summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c82
-rw-r--r--stdlib/doc-syms.tl8
-rw-r--r--txr.1108
3 files changed, 161 insertions, 37 deletions
diff --git a/eval.c b/eval.c
index d95672f7..57d6dede 100644
--- a/eval.c
+++ b/eval.c
@@ -109,7 +109,7 @@ val const_foldable_s;
val pct_fun_s;
val special_s, unbound_s;
-val whole_k, form_k, symacro_k;
+val whole_k, form_k, symacro_k, macro_k;
val last_form_evaled;
@@ -765,59 +765,87 @@ static val special_var_p(val sym)
if2(autoload_try_var(sym), gethash(special, sym)));
}
-static val lexical_var_p(val menv, val sym)
+static val lexical_binding_kind(val menv, val sym)
{
if (nilp(menv)) {
return nil;
- } else if (special_var_p(sym)) {
- return nil;
} else {
- type_check(lit("lexical-var-p"), menv, ENV);
+ type_check(lit("lexical-binding-kind"), menv, ENV);
{
val binding = assoc(sym, menv->e.vbindings);
- if (binding) /* special_s: see make_var_shadowing_env */
- return tnil(cdr(binding) == special_s);
- return lexical_var_p(menv->e.up_env, sym);
+ if (binding) {
+ /* special_s: see make_var_shadowing_env */
+ if (cdr(binding) != special_s)
+ return symacro_k;
+ else if (special_var_p(sym))
+ return nil;
+ return var_k;
+ }
}
+
+ return lexical_binding_kind(menv->e.up_env, sym);
}
}
-static val old_lexical_var_p(val menv, val sym)
+static val lexical_fun_binding_kind(val menv, val sym)
{
if (nilp(menv)) {
return nil;
} else {
- type_check(lit("lexical-var-p"), menv, ENV);
+ type_check(lit("lexical-fun-binding-kind"), menv, ENV);
{
- val binding = assoc(sym, menv->e.vbindings);
+ val binding = assoc(sym, menv->e.fbindings);
+ /* special_s: see make_var_shadowing_env */
if (binding)
- return tnil(cdr(binding) == special_s);
- return lexical_var_p(menv->e.up_env, sym);
+ return if3(cdr(binding) == special_s,
+ fun_k, macro_k);
}
+
+ return lexical_fun_binding_kind(menv->e.up_env, sym);
}
}
-static val lexical_fun_p(val menv, val sym)
+static val lexical_var_p(val menv, val sym)
+{
+ return eq(lexical_binding_kind(menv, sym), var_k);
+}
+
+static val lexical_symacro_p(val menv, val sym)
+{
+ return eq(lexical_binding_kind(menv, sym), symacro_k);
+}
+
+static val old_lexical_var_p(val menv, val sym)
{
if (nilp(menv)) {
return nil;
} else {
- type_check(lit("lexical-fun-p"), menv, ENV);
+ type_check(lit("lexical-var-p"), menv, ENV);
{
- val binding = assoc(sym, menv->e.fbindings);
+ val binding = assoc(sym, menv->e.vbindings);
- if (binding) /* special_s: see make_var_shadowing_env */
+ if (binding)
return tnil(cdr(binding) == special_s);
- return lexical_fun_p(menv->e.up_env, sym);
+ return lexical_var_p(menv->e.up_env, sym);
}
}
}
+static val lexical_fun_p(val menv, val sym)
+{
+ return eq(lexical_fun_binding_kind(menv, sym), fun_k);
+}
+
+static val lexical_macro_p(val menv, val sym)
+{
+ return eq(lexical_fun_binding_kind(menv, sym), macro_k);
+}
+
static val lexical_lisp1_binding(val menv, val sym)
{
if (nilp(menv)) {
@@ -828,9 +856,14 @@ static val lexical_lisp1_binding(val menv, val sym)
{
val binding = assoc(sym, menv->e.vbindings);
- if (binding) /* special_s: see make_var_shadowing_env */
- return if3(cdr(binding) == special_s,
- var_k, symacro_k);
+ if (binding) {
+ /* special_s: see make_var_shadowing_env */
+ if (cdr(binding) != special_s)
+ return symacro_k;
+ else if (special_var_p(sym))
+ return nil;
+ return var_k;
+ }
}
{
@@ -7055,6 +7088,7 @@ void eval_init(void)
special_s = intern(lit("special"), system_package);
unbound_s = make_sym(lit("unbound"));
symacro_k = intern(lit("symacro"), keyword_package);
+ macro_k = intern(lit("macro"), keyword_package);
prof_s = intern(lit("prof"), user_package);
switch_s = intern(lit("switch"), system_package);
struct_s = intern(lit("struct"), user_package);
@@ -7426,7 +7460,13 @@ void eval_init(void)
reg_fun(intern(lit("env-fbindings"), user_package), func_n1(env_fbindings));
reg_fun(intern(lit("env-next"), user_package), func_n1(env_next));
reg_fun(intern(lit("lexical-var-p"), user_package), func_n2(lexical_var_p));
+ reg_fun(intern(lit("lexical-symacro-p"), user_package), func_n2(lexical_symacro_p));
reg_fun(intern(lit("lexical-fun-p"), user_package), func_n2(lexical_fun_p));
+ reg_fun(intern(lit("lexical-macro-p"), user_package), func_n2(lexical_macro_p));
+ reg_fun(intern(lit("lexical-binding-kind"), user_package),
+ func_n2(lexical_binding_kind));
+ reg_fun(intern(lit("lexical-fun-binding-kind"), user_package),
+ func_n2(lexical_fun_binding_kind));
reg_fun(intern(lit("lexical-lisp1-binding"), user_package),
func_n2(lexical_lisp1_binding));
reg_fun(intern(lit("chain"), user_package), func_n0v(chainv));
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 497b27a1..79a52f39 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -1150,9 +1150,13 @@
("less" "N-01D6CEA1")
("let" "N-013AF20B")
("let*" "N-013AF20B")
- ("lexical-fun-p" "N-007B1A53")
+ ("lexical-binding-kind" "N-01E65971")
+ ("lexical-fun-binding-kind" "N-01B4FFA6")
+ ("lexical-fun-p" "N-021EC6D2")
("lexical-lisp1-binding" "N-02D124AB")
- ("lexical-var-p" "N-007B1A53")
+ ("lexical-macro-p" "N-021EC6D2")
+ ("lexical-symacro-p" "N-021EC6D2")
+ ("lexical-var-p" "N-021EC6D2")
("lgamma" "D-0086")
("lib-version" "N-032F57D4")
("line" "N-02D5D09D")
diff --git a/txr.1 b/txr.1
index ede8d78e..63fece15 100644
--- a/txr.1
+++ b/txr.1
@@ -41187,13 +41187,15 @@ to discover the identities of the variables and functions which are used inside
that form, whose definitions come from a specific, bounded scope surrounding
that form.
-.coNP Functions @ lexical-var-p and @ lexical-fun-p
+.coNP Functions @, lexical-var-p @, lexical-fun-p @ lexical-symacro-p and @ lexical-macro-p
.synb
.mets (lexical-var-p < env << form )
.mets (lexical-fun-p < env << form )
+.mets (lexical-symacro-p < env << form )
+.mets (lexical-macro-p < env << form )
.syne
.desc
-These two functions are useful to macro writers. They are intended
+These four functions are useful to macro writers. They are intended
to be called from the bodies of macro expanders, such as the bodies of
.code defmacro
or
@@ -41206,8 +41208,12 @@ via the special
parameter. Using these functions, a macro can enquire whether
a given
.meta form
-is a symbol which has a variable binding or a function binding
-in the local lexical environment.
+is, respectively, a symbol which has a variable binding, a function binding,
+a symbol macro (defined by
+.codn symacrolet )
+or a macro (defined by
+.codn macrolet )
+in the environment of the macro's invocation.
This information is known during macro expansion. The macro expander
recognizes lexical function and variable bindings, because these
bindings can shadow macros.
@@ -41244,7 +41250,15 @@ Similarly,
.code lexical-fun-p
returns
.code nil
-for global functions.
+for global functions,
+.code lexical-symacro-p
+returns
+.code nil
+for global symbol macros and
+.code lexical-macro-p
+returns
+.code nil
+for global macros.
.TP* Example:
@@ -41280,15 +41294,66 @@ for global functions.
.TP* Note:
-These functions do not call
-.code macroexpand
-on the form. In most cases, it is necessary for the macro writers
-to do so. Not that in the above example, symbol
-.code y
-is classified as neither a lexical function nor variable.
-However, it can be macro-expanded to
-.code x
-which is a lexical variable.
+.coNP Function @ lexical-binding-kind
+.synb
+.mets (lexical-binding-kind < env << symbol )
+.syne
+.desc
+The
+.code lexical-binding-kind
+function inspects the macro-time environment
+.meta env
+to determine what kind of binding, if any, does
+.meta symbol
+have in the the variable namespace of that environment.
+
+If the innermost binding for
+.meta symbol
+is a variable binding, then either
+.code :var
+is returned if the variable is lexical, otherwise
+.code nil
+is returned if the variable is special.
+
+If the innermost binding for
+.meta symbol
+is a symbol macro, then
+.code :symacro
+is returned.
+
+In all other cases,
+.code nil
+is returned. The function does not consider global symbol macros
+or global lexical variables.
+
+.coNP Function @ lexical-fun-binding-kind
+.synb
+.mets (lexical-fun-binding-kind < env << symbol )
+.syne
+.desc
+The
+.code lexical-fun-binding-kind
+function inspects the macro-time environment
+.meta env
+to determine what kind of binding, if any, does
+.meta symbol
+have in the the function namespace of that environment.
+
+If the innermost binding for
+.meta symbol
+is a function binding, then
+.code :fun
+is returned.
+
+If the innermost binding for
+.meta symbol
+is a macro, then
+.code :macro
+is returned.
+
+In all other cases,
+.code nil
+is returned. The function does not consider global macros or functions.
.coNP Function @ lexical-lisp1-binding
.synb
@@ -41319,12 +41384,27 @@ If no such lexical binding is found, then the function
returns
.codn nil .
+Note that
+.code :var
+is never returned for a special variable, but such a variable
+can be shadowed by a symbol macro, in which case
+.code :symacro
+is returned.
+
Note that a
.code nil
return doesn't mean that the symbol doesn't have a lexical binding. It could
have an operator macro lexical binding (a macro binding in the function
namespace established by
.codn macrolet ).
+Unlike the
+.code lexical-binding-kind
+function, the
+.code lexical-lisp1-binding
+function never returns
+.code :macro
+because Lisp-1-style evaluation of symbols is blind to the existence of macros,
+other than symbol macros.
.coNP Operator @ defsymacro
.synb