summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-10-25 23:04:48 -0400
committerKaz Kylheku <kaz@kylheku.com>2011-10-25 23:04:48 -0400
commit2987f69f690d8433ad3aaa9e9f41949455ada2cb (patch)
treeb08a9038924133265563690bab95ac8b6d79fc17
parent4e61cfe45d3fa26f73870c0242798c9d42eb5baf (diff)
downloadtxr-2987f69f690d8433ad3aaa9e9f41949455ada2cb.tar.gz
txr-2987f69f690d8433ad3aaa9e9f41949455ada2cb.tar.bz2
txr-2987f69f690d8433ad3aaa9e9f41949455ada2cb.zip
* filter.c (function_filter): Function removed.
(get_filter): Treat (:fun ...) syntax as a single function call with extra arguments, currying it up as curried function that invokes match_funcall once. * match.c (match_funcall): Extended to take a list of the additional arguments from get_filter. Adds these to the function call form generated for the v_func call. * match.h (match_funcall): Declaration updated. * txr.1: Function Filter additional arguments documented.
-rw-r--r--filter.c8
-rw-r--r--match.c17
-rw-r--r--match.h2
-rw-r--r--txr.147
4 files changed, 56 insertions, 18 deletions
diff --git a/filter.c b/filter.c
index dc9c2ac2..770a4b4e 100644
--- a/filter.c
+++ b/filter.c
@@ -137,17 +137,11 @@ static val compound_filter(val filter_list, val string)
return reduce_left(func_n2(string_filter), filter_list, string, nil);
}
-static val function_filter(val functions, val string)
-{
- return reduce_left(swap_12_21(func_n2(match_funcall)),
- functions, string, nil);
-}
-
val get_filter(val spec)
{
if (consp(spec)) {
if (car(spec) == fun_k) {
- return curry_12_2(func_n2(function_filter), rest(spec));
+ return curry_123_2(func_n3(match_funcall), second(spec), rest(rest(spec)));
} else {
val filter_list = mapcar(func_n1(get_filter), spec);
diff --git a/match.c b/match.c
index 49a0a125..5fe8782f 100644
--- a/match.c
+++ b/match.c
@@ -2819,14 +2819,17 @@ repeat_spec_same_data:
return cons(c.bindings, if3(c.data, cons(c.data, c.data_lineno), t));
}
-val match_funcall(val name, val arg)
+val match_funcall(val name, val arg, val other_args)
{
cons_bind (in_spec, in_bindings, uw_get_match_context());
spec_bind (specline, spec_linenum, first_spec, in_spec);
- val arg1_sym = make_sym(lit("arg1")), arg2_sym = make_sym(lit("arg2"));
- val bindings = cons(cons(arg1_sym, arg), in_bindings);
+ val in_arg_sym = make_sym(lit("in_arg"));
+ val out_arg_sym = make_sym(lit("out_arg"));
+ val bindings = cons(cons(in_arg_sym, arg), in_bindings);
val spec = cons(list(spec_linenum,
- list(name, arg1_sym, arg2_sym, nao), nao), nil);
+ cons(name,
+ cons(in_arg_sym, cons(out_arg_sym, other_args))),
+ nao), nil);
match_files_ctx nc;
(void) first_spec;
@@ -2834,17 +2837,17 @@ val match_funcall(val name, val arg)
if (ret == nil)
sem_error(spec_linenum, lit("filter: (~s ~s ~s) failed"), name,
- arg, arg2_sym, nao);
+ arg, out_arg_sym, nao);
if (ret == decline_k)
sem_error(spec_linenum, lit("filter: function ~s not found"), name, nao);
{
- val out = assoc(nc.bindings, arg2_sym);
+ val out = assoc(nc.bindings, out_arg_sym);
if (!out)
sem_error(spec_linenum,
lit("filter: (~s ~s ~s) did not bind ~s"), name,
- arg, arg2_sym, arg2_sym, nao);
+ arg, out_arg_sym, out_arg_sym, nao);
return cdr(out);
}
}
diff --git a/match.h b/match.h
index 6a3002b4..00eb1f1d 100644
--- a/match.h
+++ b/match.h
@@ -25,6 +25,6 @@
*/
void match_init(void);
-val match_funcall(val name, val arg);
+val match_funcall(val name, val arg, val other_args);
int extract(val spec, val filenames, val bindings);
extern val choose_s;
diff --git a/txr.1 b/txr.1
index cf376a09..223f464d 100644
--- a/txr.1
+++ b/txr.1
@@ -3041,12 +3041,14 @@ A function can be used as a filter. For this to be possible, the function must
conform to certain rules:
.IP 1.
-The function must take exactly two arguments.
+The function must take two special arguments, which may be followed
+by additional arguments.
.IP 2.
When the function is called, the first argument will be bound to a string,
-and the second argument will be unbound. The function must produce a string
-value by binding it to the second argument.
+and the second argument will be unbound. The function must produce a
+value by binding it to the second argument. If the filter is to be used
+as the final filter in a chain, it must produce a string.
For instance, the following is a valid filter function:
@@ -3078,6 +3080,45 @@ Of course, function filters can be used in a chain:
...
@(end)
+Here is a split function which takes an extra argument.
+
+ @(define split (in out sep))
+ @ (next :list in)
+ @ (coll)@(maybe)@token@sep@(or)@token@(end)@(end)
+ @ (bind out token)
+ @(end)
+
+Furthermore, note that it produces a list rather than a string.
+This function separates the argument in into tokens according to the
+separator text sep.
+
+Here is another function, join, which catenates a list:
+
+ @(define join (in out sep))
+ @ (output :into out)
+ @ (rep)@in@sep@(last)@in@(end)
+ @ (end)
+ @(end)
+
+Now here is these two being used in a chain:
+
+ @(bind text "how,are,you")
+ @(output :filter (:fun split ",") (:fun join "-"))
+ @text
+ @(end)
+
+Output:
+
+ how-are-you
+
+When the filter invokes a function, it generates the first two arguments
+internally to pass in the input value and capture the output. The remaining
+arguments from the (:fun ...) construct are also passed to the function.
+Thus the "," and "-" are passed as the sep argument to split and join.
+
+Note that split puts out a list, which join accepts. So the overall filter
+chain operates on a string: a string goes into split, and a string comes out of
+join.
.SS The Deffilter Directive