diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-01-19 04:34:18 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-01-19 04:34:18 -0800 |
commit | c5a77bdebfe7daa83eacd6b4e3e208473b5f9ad2 (patch) | |
tree | 08f6771c4c04dc563148e33b915bdcd618c866bb | |
parent | ca741785bfccf52448c5e9a9bdd82778fc976f51 (diff) | |
download | txr-c5a77bdebfe7daa83eacd6b4e3e208473b5f9ad2.tar.gz txr-c5a77bdebfe7daa83eacd6b4e3e208473b5f9ad2.tar.bz2 txr-c5a77bdebfe7daa83eacd6b4e3e208473b5f9ad2.zip |
Bugfix: expand macros in collect, coll, gather.
In the argument lists of @(collect)/@(repeat), @(coll)/@(rep)
and @(gather), Lisp expressions can appear as arguments
to keywords or for supplying default values for variables.
These are not being macro-expanded.
* match.c (match_expand_vars): New static function.
(match_expand_keyword_args): New function.
* match.h (match_expand_keyword_args): Declared.
* parser.y (gather_clause, collect_clause, elem): Use new
function in match.c to expand the argument lists.
-rw-r--r-- | match.c | 52 | ||||
-rw-r--r-- | match.h | 1 | ||||
-rw-r--r-- | parser.y | 40 |
3 files changed, 77 insertions, 16 deletions
@@ -2860,6 +2860,58 @@ static val v_gather(match_files_ctx *c) return next_spec_k; } + +static val match_expand_vars(val vars) +{ + list_collect_decl (out, ptail); + + for (; vars; vars = cdr(vars)) { + val var = car(vars); + if (consp(var)) { + val sym = car(var); + val dfl = cadr(var); + val dfl_ex = expand(dfl, nil); + + ptail = list_collect(ptail, if3(dfl == dfl_ex, + var, list(sym, dfl_ex, nao))); + } else { + ptail = list_collect(ptail, var); + } + } + + return out; +} + +val match_expand_keyword_args(val args) +{ + list_collect_decl (out, ptail); + + if (opt_compat && opt_compat <= 165) + return args; + + while (consp(args)) { + val sym = car(args); + if (sym == maxgap_k || sym == mingap_k || sym == gap_k || sym == times_k || + sym == mintimes_k || sym == maxtimes_k || sym == lines_k || + sym == counter_k || sym == vars_k) + { + val d = cdr(args); + val form = car(d); + val form_ex = if3(sym == vars_k, + match_expand_vars(form), + expand(form, nil)); + ptail = list_collect(ptail, sym); + ptail = list_collect(ptail, form_ex); + args = cdr(d); + } else { + ptail = list_collect(ptail, sym); + args = cdr(args); + } + } + + return out; +} + static val v_collect(match_files_ctx *c) { spec_bind (specline, first_spec, c->spec); @@ -28,6 +28,7 @@ extern val text_s, choose_s, gather_s, do_s, require_s; extern val close_s, load_s, include_s, mod_s, modlast_s, line_s; extern val counter_k, vars_k, env_k, var_k; +val match_expand_keyword_args(val elem); val match_filter(val name, val arg, val other_args); val match_fun(val name, val args, val input, val files); val include(val specline); @@ -282,20 +282,22 @@ choose_clause : CHOOSE exprs_opt ')' gather_clause : GATHER exprs_opt ')' newl gather_parts - END newl { $$ = list(gather_s, + END newl { val args = match_expand_keyword_args($2); + $$ = list(gather_s, append2(mapcar(curry_12_1(func_n2(cons), nil), first($5)), rest($5)), - $2, nao); + args, nao); rl($$, num($1)); } | GATHER exprs_opt ')' newl gather_parts until_last exprs_opt ')' newl clauses_opt - END newl { $$ = list(gather_s, + END newl { val args = match_expand_keyword_args($2); + $$ = list(gather_s, append2(mapcar(curry_12_1(func_n2(cons), nil), first($5)), rest($5)), - $2, cons(cdr($6), + args, cons(cdr($6), cons($7, $10)), nao); rl($$, num($1)); } @@ -314,19 +316,21 @@ additional_gather_parts : AND newl gather_parts { $$ = $3; } ; collect_clause : collect_repeat exprs_opt ')' newl - clauses_opt END newl { $$ = list(car($1), - $5, nil, $2, - nao); - rl($$, cdr($1)); } + clauses_opt END newl { val args = match_expand_keyword_args($2); + $$ = list(car($1), + $5, nil, args, + nao); + rl($$, cdr($1)); } | collect_repeat exprs_opt ')' newl clauses_opt until_last exprs_opt ')' newl clauses_opt END newl - { if (nilp($10)) + { val args = match_expand_keyword_args($2); + if (nilp($10)) yyerr("empty until/last in collect"); $$ = list(car($1), $5, cons(cdr($6), cons($7, $10)), - $2, nao); + args, nao); rl($$, cdr($1)); rl($10, car($6)); } | collect_repeat exprs_opt ')' @@ -445,23 +449,27 @@ elem : texts { $$ = rlcp(cons(text_s, $1), $1); $$ = rlcp(cons(sym, expand_meta(rest($1), nil)), $1); } - | COLL exprs_opt ')' elems_opt END { $$ = list(coll_s, $4, nil, $2, nao); + | COLL exprs_opt ')' elems_opt END { val args = match_expand_keyword_args($2); + $$ = list(coll_s, $4, nil, args, nao); rl($$, num($1)); } | COLL exprs_opt ')' elems_opt until_last exprs_opt ')' - elems_opt END { $$ = list(coll_s, $4, cons(cdr($5), + elems_opt END { val args = match_expand_keyword_args($2); + $$ = list(coll_s, $4, cons(cdr($5), cons($6, $8)), - $2, nao); + args, nao); rl($$, num($1)); rl($6, car($5)); } - | REP exprs_opt ')' elems END { $$ = list(rep_s, $4, nil, $2, nao); + | REP exprs_opt ')' elems END { val args = match_expand_keyword_args($2); + $$ = list(rep_s, $4, nil, args, nao); rl($$, num($1)); } | REP exprs_opt ')' elems until_last exprs_opt ')' elems END - { $$ = list(rep_s, $4, cons(cdr($5), + { val args = match_expand_keyword_args($2); + $$ = list(rep_s, $4, cons(cdr($5), cons($6, $8)), - $2, nao); + args, nao); rl($$, num($1)); rl($6, car($5)); } | COLL error { $$ = nil; |