summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--eval.c36
-rw-r--r--match.c42
-rw-r--r--parser.y9
-rw-r--r--txr.117
-rw-r--r--txr.vim2
6 files changed, 71 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index f132e31b..15148d4d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
2012-02-18 Kaz Kylheku <kaz@kylheku.com>
+ Allow braced output variables to actually be arbitrary substitutions.
+
+ * eval.c (subst_vars): Treat the variable as an arbitrary
+ expression rather than just a symbol.
+
+ * match.c (subst_vars): Likewise.
+
+ * parser.y (o_var): Further simplification. The first item in
+ an output var is an expr and not an IDENT.
+
+ * txr.1: Updated.
+
+ * txr.vim: Likewise.
+
+2012-02-18 Kaz Kylheku <kaz@kylheku.com>
+
* parser.y (o_var): Remove productions from grammar by using exprs_opt.
2012-02-17 Kaz Kylheku <kaz@kylheku.com>
diff --git a/eval.c b/eval.c
index 3a072c77..9380df06 100644
--- a/eval.c
+++ b/eval.c
@@ -1118,29 +1118,23 @@ static val subst_vars(val forms, val env)
val sym = first(form);
if (sym == var_s) {
- val sym = second(form);
+ val expr = second(form);
val pat = third(form);
val modifiers = fourth(form);
- val pair = lookup_var(env, sym);
-
- if (pair) {
- val str = cdr(pair);
-
- if (!stringp(str) && !listp(str))
- str = format(nil, lit("~a"), str, nao);
-
- if (pat)
- forms = cons(str, cons(pat, rest(forms)));
- else if (modifiers)
- forms = cons(format_field(str, modifiers, nil,
- curry_123_1(func_n3(eval), env, form)),
- rest(forms));
- else
- forms = cons(str, rest(forms));
- continue;
- }
- uw_throwf(query_error_s, lit("unbound variable ~a"),
- sym, nao);
+ val str = eval(expr, env, form);
+
+ if (!stringp(str) && !listp(str))
+ str = format(nil, lit("~a"), str, nao);
+
+ if (pat)
+ forms = cons(str, cons(pat, rest(forms)));
+ else if (modifiers)
+ forms = cons(format_field(str, modifiers, nil,
+ curry_123_1(func_n3(eval), env, form)),
+ rest(forms));
+ else
+ forms = cons(str, rest(forms));
+ continue;
} else if (sym == quasi_s) {
val nested = subst_vars(rest(form), env);
list_collect_append(iter, nested);
diff --git a/match.c b/match.c
index d921757e..d253913a 100644
--- a/match.c
+++ b/match.c
@@ -1316,37 +1316,31 @@ static val subst_vars(val spec, val bindings, val filter)
val sym = first(elem);
if (sym == var_s) {
- val sym = second(elem);
+ val expr = second(elem);
val pat = third(elem);
val modifiers = fourth(elem);
- val pair = assoc(sym, bindings);
+ val str = txeval(spec, expr, bindings);
- if (pair) {
- val str = cdr(pair);
+ if (!stringp(str) && !listp(str))
+ str = format(nil, lit("~a"), str, nao);
- if (!stringp(str) && !listp(str))
- str = format(nil, lit("~a"), str, nao);
+ if (pat)
+ spec = cons(pat, rest(spec));
- if (pat)
- spec = cons(pat, rest(spec));
-
- if (modifiers) {
- spec = cons(format_field(str, modifiers, filter,
- curry_123_2(func_n3(txeval), spec, bindings)),
- rest(spec));
- } else {
- if (listp(str))
- str = cat_str(mapcar(func_n1(tostringp), str), lit(" "));
- else
- str = if3(stringp(str), str, tostringp(str));
-
- spec = cons(filter_string(filter, str), rest(spec));
- }
+ if (modifiers) {
+ spec = cons(format_field(str, modifiers, filter,
+ curry_123_2(func_n3(txeval), spec, bindings)),
+ rest(spec));
+ } else {
+ if (listp(str))
+ str = cat_str(mapcar(func_n1(tostringp), str), lit(" "));
+ else
+ str = if3(stringp(str), str, tostringp(str));
- continue;
+ spec = cons(filter_string(filter, str), rest(spec));
}
- uw_throwf(query_error_s, lit("unbound variable ~a"),
- sym, nao);
+
+ continue;
} else if (sym == quasi_s) {
val nested = subst_vars(rest(elem), bindings, filter);
list_collect_append(iter, nested);
diff --git a/parser.y b/parser.y
index 7dc5d67b..ebcf63b3 100644
--- a/parser.y
+++ b/parser.y
@@ -636,11 +636,10 @@ o_var : IDENT { $$ = list(var_s, intern(string_own($1), nil),
nao); }
| IDENT o_elem { $$ = list(var_s, intern(string_own($1), nil),
$2, nao); }
- | '{' IDENT exprs_opt '}' { $$ = list(var_s, intern(string_own($2), nil),
- nil, $3, nao); }
- | '{' IDENT exprs_opt '}' o_elem
- { $$ = list(var_s, intern(string_own($2), nil),
- $5, $3, nao); }
+ | '{' expr exprs_opt '}'
+ { $$ = list(var_s, $2, nil, $3, nao); }
+ | '{' expr exprs_opt '}' o_elem
+ { $$ = list(var_s, $2, $5, $3, nao); }
| IDENT error { $$ = nil;
yybadtoken(yychar, lit("variable spec")); }
;
diff --git a/txr.1 b/txr.1
index 79943997..98a1387a 100644
--- a/txr.1
+++ b/txr.1
@@ -3334,6 +3334,8 @@ for the output clause. The syntax for this is @(NAME :filter <filterspec>}.
The filter specification syntax is the same as in the output clause.
See Output Filtering below.
+.SS Output Variables: Indexing
+
Additional syntax is supported in output variables that is does not appear
in pattern matching variables.
@@ -3367,6 +3369,21 @@ The above produces the text "b,c" in a field 10 spaces wide. The [1..3]
argument extracts a range of a; the "," argument specifies an alternate
separator string, and 10 specifies the field width.
+.SS Output Substitutions
+
+The brace syntax has another syntactic and semantic extension. In place
+of the symbol, an expression may appear. The value of that expression
+is substituted.
+
+Example:
+
+ @(bind a "foo")
+ @(output)
+ @{`@a:` -10}
+
+Here, the quasiliteral expression `@a:` is evaluated, producing the string
+"foo:". This string is printed right-adjusted in a 10 character field.
+
.SS The Repeat Directive
The repeat directive is generates repeated text from a ``boilerplate'',
diff --git a/txr.vim b/txr.vim
index 4d2f4805..6f202d14 100644
--- a/txr.vim
+++ b/txr.vim
@@ -108,7 +108,7 @@ syn match txr_ncomment ";.*" contained
syn match txr_ident "[A-Za-z0-9!$%&*+\-<=>?\\^_~]\+" contained
syn match txr_num "[+-]\?[0-9]\+" contained
-syn region txr_bracevar matchgroup=Delimiter start="@[ \t]*[*]\?{" matchgroup=Delimiter end="}" contains=txr_num,txr_ident,txr_string,txr_dwim,txr_list,txr_regex,txr_quasilit,txr_chr
+syn region txr_bracevar matchgroup=Delimiter start="@[ \t]*[*]\?{" matchgroup=Delimiter end="}" contains=txr_num,txr_meta,txr_metabkt,txr_ident,txr_string,txr_dwim,txr_list,txr_regex,txr_quasilit,txr_chr
syn region txr_directive matchgroup=Delimiter start="@[ \t]*(" matchgroup=Delimiter end=")" contains=txr_keyword,txr_string,txr_list,txr_dwim,txr_metabkt,txr_meta,txr_quasilit,txr_num,txr_ident,txr_regex,txr_string,txr_variable,txr_chr,txr_hash,txr_ncomment