summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-12-26 20:14:13 -0800
committerKaz Kylheku <kaz@kylheku.com>2015-12-26 20:14:13 -0800
commit837b0f15d86b21665fdf7c5d55cbe4ecd6d42ea4 (patch)
tree51014445b28a04de955cbdc8bd251538e464f8c0 /eval.c
parent5335d788dc601a50fc26319d39b21bdcaf1457b6 (diff)
downloadtxr-837b0f15d86b21665fdf7c5d55cbe4ecd6d42ea4.tar.gz
txr-837b0f15d86b21665fdf7c5d55cbe4ecd6d42ea4.tar.bz2
txr-837b0f15d86b21665fdf7c5d55cbe4ecd6d42ea4.zip
TXR quasiliterals and output vars treated as Lisp.
* eval.c (format_field): Function moved here from match.c, along with the introduction of a new behavior: if a meta-expr occurs among the modifiers, its constituent expression is evaluated in its place. This allows for @{a @[expr]} which was previously not allowed in Lisp quasiliterals, but worked in TXR quasiliterals due to the treatment of @ by txeval. (subst_vars): Static function turns external, so code in match.c can call it instead of the subst_vars in that module. For that purpose, it needs to take a filter argument and process filters, like the match.c subst_vars. (op_quasi_lit): Pass nil as filter argument to subst_vars. * eval.h (format_field, subst_vars): Declared. * match.c (format_field): Function removed, moved to eval.c and slightly changed. (subst_vars): Renamed to tx_subst_vars. By default, now just a wrapper for subst_vars. In compatibility mode, invokes the old logic. (do_txeval, do_output_line): Call tx_subst_vars rather than subst_vars. * match.h (format_field): Declaration removed. * parser.y (expr): Grammar production removed: no longer referenced. (o_var): Braced variable case now parsed as n_expr, and expanded as expr by default, since this is Lisp now. In compatibility mode, expanded using expand_meta. Also SYMTOK case must be subject to expansion; an output var can now be a symbol macro. (expand_meta): Expand a quasi-literal as Lisp, except in compatibility mode. * txr.1: Bit of a documentation update. Existing doc isn't totally clear.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c109
1 files changed, 102 insertions, 7 deletions
diff --git a/eval.c b/eval.c
index 9edc6ae6..a63f369b 100644
--- a/eval.c
+++ b/eval.c
@@ -53,6 +53,7 @@
#include "lisplib.h"
#include "struct.h"
#include "cadr.h"
+#include "filter.h"
#include "eval.h"
#define max(a, b) ((a) > (b) ? (a) : (b))
@@ -2114,7 +2115,101 @@ static val op_handler_bind(val form, val env)
return result;
}
-static val subst_vars(val forms, val env)
+val format_field(val obj, val modifier, val filter, val eval_fun)
+{
+ val n = zero, sep = lit(" ");
+ val plist = nil;
+ val str;
+
+ for (; modifier; pop(&modifier)) {
+ val item = first(modifier);
+ if (regexp(item)) {
+ uw_throw(query_error_s, lit("bad field format: regex modifier in output"));
+ } else if (keywordp(item)) {
+ plist = modifier;
+ break;
+ } else if ((!opt_compat || opt_compat > 128) &&
+ consp(item) && car(item) == expr_s)
+ {
+ item = cdr(item);
+ goto eval;
+ } else if (consp(item) && car(item) == dwim_s) {
+ val arg_expr = second(item);
+
+ if (consp(arg_expr) && car(arg_expr) == range_s) {
+ val from = funcall1(eval_fun, second(arg_expr));
+ val to = funcall1(eval_fun, third(arg_expr));
+
+ obj = sub(obj, from, to);
+ } else {
+ val arg = funcall1(eval_fun, arg_expr);
+ if (bignump(arg) || fixnump(arg)) {
+ obj = ref(obj, arg);
+ } else if (rangep(arg)) {
+ obj = sub(obj, from(arg), to(arg));
+ } else {
+ uw_throwf(query_error_s, lit("format_field: bad index: ~s"),
+ arg, nao);
+ }
+ }
+ } else eval: {
+ val v = funcall1(eval_fun, item);
+ if (fixnump(v))
+ n = v;
+ else if (stringp(v))
+ sep = v;
+ else
+ uw_throwf(query_error_s,
+ lit("bad field format: bad modifier object: ~s"),
+ item, nao);
+ }
+ }
+
+ if (listp(obj))
+ str = cat_str(mapcar(func_n1(tostringp), obj), sep);
+ else
+ str = if3(stringp(obj), obj, tostringp(obj));
+
+ {
+ val filter_sym = getplist(plist, filter_k);
+
+ if (filter_sym) {
+ filter = get_filter(filter_sym);
+
+ if (!filter) {
+ uw_throwf(query_error_s,
+ lit("bad field format: ~s specifies unknown filter"),
+ filter_sym, nao);
+ }
+ }
+
+ if (filter)
+ str = filter_string_tree(filter, str);
+ }
+
+ {
+ val right = lt(n, zero);
+ val width = if3(lt(n, zero), neg(n), n);
+ val diff = minus(width, length_str(str));
+
+ if (le(diff, zero))
+ return str;
+
+ if (ge(length_str(str), width))
+ return str;
+
+ {
+ val padding = mkstring(diff, chr(' '));
+
+ return if3(right,
+ cat_str(list(padding, str, nao), nil),
+ cat_str(list(str, padding, nao), nil));
+ }
+ }
+}
+
+
+val subst_vars(val forms, val env, val filter)
{
list_collect_decl(out, iter);
@@ -2136,18 +2231,18 @@ static val subst_vars(val forms, val env)
str = tostringp(str);
if (modifiers) {
- forms = cons(format_field(str, modifiers, nil,
+ forms = cons(format_field(str, modifiers, filter,
curry_123_1(func_n3(eval), env, form)),
rest(forms));
} else {
if (listp(str))
str = cat_str(mapcar(func_n1(tostringp), str), lit(" "));
- forms = cons(str, rest(forms));
+ forms = cons(filter_string_tree(filter, str), rest(forms));
}
continue;
} else if (sym == quasi_s) {
- val nested = subst_vars(rest(form), env);
+ val nested = subst_vars(rest(form), env, filter);
iter = list_collect_append(iter, nested);
forms = cdr(forms);
continue;
@@ -2157,10 +2252,10 @@ static val subst_vars(val forms, val env)
str = cat_str(mapcar(func_n1(tostringp), str), lit(" "));
else if (!stringp(str))
str = tostringp(str);
- forms = cons(str, rest(forms));
+ forms = cons(filter_string_tree(filter, tostringp(str)), rest(forms));
continue;
} else {
- val nested = subst_vars(form, env);
+ val nested = subst_vars(form, env, filter);
iter = list_collect_append(iter, nested);
forms = cdr(forms);
continue;
@@ -2179,7 +2274,7 @@ static val subst_vars(val forms, val env)
static val op_quasi_lit(val form, val env)
{
- return cat_str(subst_vars(rest(form), env), nil);
+ return cat_str(subst_vars(rest(form), env, nil), nil);
}
static val op_with_saved_vars(val form, val env)