diff options
-rw-r--r-- | eval.c | 82 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 8 | ||||
-rw-r--r-- | txr.1 | 108 |
3 files changed, 161 insertions, 37 deletions
@@ -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") @@ -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 |