summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-01-21 21:13:33 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-01-21 21:13:33 -0800
commitb64bcbb6e7bd7f331f660518e97e2bfa898ae340 (patch)
tree8b80eb794c7f4777346947fccea8b0faafeb4185
parent9cac065f8374ed008bf8274909b3f431dd9e8da6 (diff)
downloadtxr-b64bcbb6e7bd7f331f660518e97e2bfa898ae340.tar.gz
txr-b64bcbb6e7bd7f331f660518e97e2bfa898ae340.tar.bz2
txr-b64bcbb6e7bd7f331f660518e97e2bfa898ae340.zip
bugfix: expand macros in a number of directives.
This is the last round of changes on this topic, bringing proper macro expansion to the arguments to @(skip), @(fuzz), @(next), @(call), @(cat), @(load) and @(close). * match.c (match_expand_keyword_args): Only process the keyword arguments if they are followed by an argument. Process @(next) arguments here too: :list and :string take a Lisp expression, but :tlist and :var take an argument which is not a Lisp expression and must be handled properly. Also, expand any non-keyword expression. This handles the <source> argument of @(next). (match_expand_elem): New function. * match.h (match_expand_elem): Declared. * parser.h (expand_meta): Declared. * parser.y (expand_meta): Static function becomes external. (elem): Expand elem other than require or do using match_expand_elem. We don't fold require and do into this because match_expand_elem has a backward compat switch in it that doesn't apply to these.
-rw-r--r--match.c80
-rw-r--r--match.h1
-rw-r--r--parser.h1
-rw-r--r--parser.y7
4 files changed, 76 insertions, 13 deletions
diff --git a/match.c b/match.c
index 40c48f40..d3c780ee 100644
--- a/match.c
+++ b/match.c
@@ -2894,27 +2894,91 @@ val match_expand_keyword_args(val 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 next = cdr(args);
+ val more = consp(next);
+
+ if (more &&
+ (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 ||
+ sym == list_k || sym == string_k))
{
- val d = cdr(args);
- val form = car(d);
+ val form = car(next);
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 {
+ args = cdr(next);
+ } else if (more &&
+ (sym == tlist_k)) {
+ ptail = list_collect(ptail, sym);
+ ptail = list_collect(ptail, expand_meta(car(next), nil));
+ args = cdr(next);
+ } else if (more &&
+ (sym == var_k)) {
ptail = list_collect(ptail, sym);
- args = cdr(args);
+ ptail = list_collect(ptail, car(next));
+ args = cdr(next);
+ } else {
+ ptail = list_collect(ptail, expand(sym, nil));
+ args = next;
}
}
return out;
}
+val match_expand_elem(val elem)
+{
+ if (atom(elem)) {
+ return elem;
+ } else {
+ val sym = car(elem);
+ val args = cdr(elem);
+
+ if (opt_compat && opt_compat < 166) {
+ goto out;
+ } else if (sym == skip_s || sym == fuzz_s || sym == load_s ||
+ sym == close_s)
+ {
+ val args_ex = expand_forms(args, nil);
+ if (args == args_ex)
+ return elem;
+ return rlcp(cons(sym, args_ex), elem);
+ } else if (sym == call_s) {
+ if (atom(args)) {
+ return elem;
+ } else {
+ val arg1 = car(args);
+ val arg1_ex = expand(arg1, nil);
+ if (arg1 == arg1_ex)
+ return elem;
+ return rlcp(cons(sym, cons(arg1_ex, cdr(args))), elem);
+ }
+ } else if (sym == cat_s) {
+ if (atom(args) || atom(cdr(args))) {
+ return elem;
+ } else {
+ val arg1 = car(args);
+ val arg2 = cadr(args);
+ val arg2_ex = expand(arg2, nil);
+ if (arg2 == arg2_ex)
+ return elem;
+ return rlcp(cons(sym, cons(arg1, cons(arg2_ex, cddr(args)))), elem);
+ }
+ } else if (sym == next_s) {
+ val args_ex = match_expand_keyword_args(args);
+ if (args == args_ex)
+ return elem;
+ return rlcp(cons(sym, args_ex), elem);
+ } else {
+out:
+ return rlcp(cons(sym, expand_meta(args, nil)), elem);
+ }
+ }
+}
+
static val v_collect(match_files_ctx *c)
{
spec_bind (specline, first_spec, c->spec);
diff --git a/match.h b/match.h
index f911897f..a3b19f0f 100644
--- a/match.h
+++ b/match.h
@@ -29,6 +29,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_expand_elem(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);
diff --git a/parser.h b/parser.h
index 658178c7..7e1396af 100644
--- a/parser.h
+++ b/parser.h
@@ -102,6 +102,7 @@ int parse_once(val stream, val name, parser_t *parser);
int parse(parser_t *parser, val name, enum prime_parser);
val source_loc(val form);
val source_loc_str(val form, val alt);
+val expand_meta(val form, val menv);
val rlset(val form, val info);
void parser_reset(parser_t *);
INLINE val rlcp(val to, val from)
diff --git a/parser.y b/parser.y
index 40e36f47..e1392878 100644
--- a/parser.y
+++ b/parser.y
@@ -63,7 +63,6 @@ static val define_transform(parser_t *parser, val define_form);
static val lit_char_helper(val litchars);
static val optimize_text(val text_form);
static val unquotes_occur(val quoted_form, int level);
-static val expand_meta(val form, val menv);
static val rlrec(parser_t *, val form, val line);
static wchar_t char_from_name(const wchar_t *name);
static val make_expr(parser_t *, val sym, val rest, val lineno);
@@ -460,9 +459,7 @@ elem : texts { $$ = rlcp(cons(text_s, $1), $1);
expand_forms(rest($1), nil)),
$1);
else
- $$ = rlcp(cons(sym,
- expand_meta(rest($1), nil)),
- $1); }
+ $$ = match_expand_elem($1); }
| COLL exprs_opt ')' elems_opt END { val args = match_expand_keyword_args($2);
$$ = list(coll_s, $4, nil, args, nao);
rl($$, num($1)); }
@@ -1445,7 +1442,7 @@ static val unquotes_occur(val quoted_form, int level)
}
}
-static val expand_meta(val form, val menv)
+val expand_meta(val form, val menv)
{
val sym;