diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-02-08 19:18:57 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-02-08 19:18:57 -0800 |
commit | 6b5958a0731236ea9c51e0d0b47fb408a14d5d09 (patch) | |
tree | 57549c92d4c1b82578a99d6ec3538b26ca6fc7a6 | |
parent | ea58260489e6de6a7d44c57254dcc10d8656d8ee (diff) | |
download | txr-6b5958a0731236ea9c51e0d0b47fb408a14d5d09.tar.gz txr-6b5958a0731236ea9c51e0d0b47fb408a14d5d09.tar.bz2 txr-6b5958a0731236ea9c51e0d0b47fb408a14d5d09.zip |
New system function: expand-with-free-refs.
This interface to the expander returns not only the expanded
form, but also a list of the free variables and functions
occurring in that form.
This interface to the expander works by installing a handler
which intercepts and muffles warnings. When a warning occurs
indicating an unbound variable or function, the information is
retained. The expander then returns the information along
with the expanded form.
* eval.c (gather_free_refs): New static function.
(expand_with_free_refs): New function.
(eval_init): Register sys:expand-with-free-refs intrinsic.
-rw-r--r-- | eval.c | 35 |
1 files changed, 35 insertions, 0 deletions
@@ -4266,6 +4266,40 @@ static val no_warn_expand(val form, val menv) return ret; } +static val gather_free_refs(val info_cons, val exc, struct args *args) +{ + (void) exc; + + if (args_count(args) == 2) { + val sym = args_get_rest(args, 2); + val tag = args_at(args, 1); + + if (tag == var_s) { + loc al = car_l(info_cons); + if (!memq(sym, deref(al))) + mpush(sym, al); + } else if (tag == fun_s) { + loc dl = cdr_l(info_cons); + if (!memq(sym, deref(dl))) + mpush(sym, dl); + } + } + + uw_throw(continue_s, nil); +} + +static val expand_with_free_refs(val form, val menv) +{ + val ret; + uw_frame_t uw_handler; + val info_cons = cons(nil, nil); + uw_push_handler(&uw_handler, cons(warning_s, nil), + func_f1v(info_cons, gather_free_refs)); + ret = expand(form, menv); + uw_pop_frame(&uw_handler); + return list(ret, car(info_cons), cdr(info_cons), nao); +} + val macro_form_p(val form, val menv) { menv = default_bool_arg(menv); @@ -5671,6 +5705,7 @@ void eval_init(void) reg_var(load_path_s, nil); reg_symacro(intern(lit("self-load-path"), user_package), load_path_s); reg_fun(intern(lit("expand"), system_package), func_n2o(no_warn_expand, 1)); + reg_fun(intern(lit("expand-with-free-refs"), system_package), func_n2o(expand_with_free_refs, 1)); reg_fun(intern(lit("macro-form-p"), user_package), func_n2o(macro_form_p, 1)); reg_fun(intern(lit("macroexpand-1"), user_package), func_n2o(macroexpand_1, 1)); |