summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--match.c29
-rw-r--r--txr.115
3 files changed, 57 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index fd8d0bfb..a4061b30 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2014-10-15 Kaz Kylheku <kaz@kylheku.com>
+
+ * match.c (subst_vars): Fix buggy rendering of TXR Lisp expressions
+ that evaluate to lists. For instance `@(list)` renders to the
+ string "nil", and `@(list 1 2)` renders as "(1 2)". The desired
+ behavior is "" and "1 2", respectively.
+ (do_output_line): In output directives, there is a similar problem.
+ A @(list) in the middle of an output block turns to nil, and
+ a @(list 1 2) renders in parentheses as (1 2). Furthermore,
+ there is the additional problem that no filtering is applied
+ to the interpolated value. These behaviors are subject to the
+ compatibility option, since they change the externally visible
+ behavior of TXR programs.
+
+ * txr.1: Document that empty lists in @(output) variable substitutions
+ turn into nothing. Document value of 100 for -C option, describing
+ the above issue.
+
2014-10-14 Kaz Kylheku <kaz@kylheku.com>
More type safety, with help from C++ compiler.
diff --git a/match.c b/match.c
index 2aee0df9..aad77c91 100644
--- a/match.c
+++ b/match.c
@@ -1422,9 +1422,19 @@ static val subst_vars(val spec, val bindings, val filter)
spec = cdr(spec);
continue;
} else if (sym == expr_s) {
- val result = eval(rest(elem), make_env(bindings, nil, nil), elem);
- spec = cons(filter_string_tree(filter, tostringp(result)), rest(spec));
- continue;
+ if (opt_compat && opt_compat < 100) {
+ val result = eval(rest(elem), make_env(bindings, nil, nil), elem);
+ spec = cons(filter_string_tree(filter, tostringp(result)), rest(spec));
+ continue;
+ } else {
+ val str = eval(rest(elem), make_env(bindings, nil, nil), elem);
+ if (listp(str))
+ str = cat_str(mapcar(func_n1(tostringp), str), lit(" "));
+ else if (!stringp(str))
+ str = tostringp(str);
+ spec = cons(filter_string_tree(filter, tostringp(str)), rest(spec));
+ continue;
+ }
} else {
val nested = subst_vars(elem, bindings, filter);
iter = list_collect_append(iter, nested);
@@ -1774,8 +1784,17 @@ static void do_output_line(val bindings, val specline, val filter, val out)
}
} else if (directive == expr_s) {
- format(out, lit("~a"),
- eval(rest(elem), make_env(bindings, nil, nil), elem), nao);
+ if (opt_compat && opt_compat < 100) {
+ format(out, lit("~a"),
+ eval(rest(elem), make_env(bindings, nil, nil), elem), nao);
+ } else {
+ val str = cat_str(subst_vars(cons(elem, nil),
+ bindings, filter), nil);
+ if (str == nil)
+ sem_error(specline, lit("bad substitution: ~a"),
+ second(elem), nao);
+ put_string(str, out);
+ }
}
}
break;
diff --git a/txr.1 b/txr.1
index e25f93c9..d84467dc 100644
--- a/txr.1
+++ b/txr.1
@@ -6731,6 +6731,7 @@ A list is converted to a string in a special way: the elements are
individually converted to a string and then they are catenated together.
The default separator string is a single space: an alternate separation
can be specified as an argument in the brace substitution syntax.
+Empty lists turn into an empty string.
Lists may be output within
.code @(repeat)
@@ -25322,6 +25323,20 @@ can be emulated is \*(TX 97.
Here are values which have a special meaning as arguments to the
.code -C
option, along with a description of what behaviors are affected:
+.IP 99
+Up to \*(TX 99, the substitution of TXR Lisp expressions in
+.code @(output)
+directives and in the quasistrings of the pattern language
+exhibited the buggy behavior that if the TXR Lisp expression
+produced a list, the list was rendered as a parenthesized
+representation, or the text
+.code nil
+in the empty list case. Moreover, in the
+.code @(output)
+case, the value of TXR Lisp expressions was not subject to filtering.
+Starting with \*(TX 100, these issues
+are fixed, making the the behavior is consistent with
+the behavior of TXR Lisp quasiliterals.
.IP 97
Up to \*(TX 97, the error exception symbols such as
.code file-error