diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | lib.c | 41 | ||||
-rw-r--r-- | lib.h | 3 | ||||
-rw-r--r-- | match.c | 37 | ||||
-rw-r--r-- | txr.1 | 9 |
5 files changed, 89 insertions, 19 deletions
@@ -1,5 +1,23 @@ 2011-11-19 Kaz Kylheku <kaz@kylheku.com> + deffilter grows in power: it can take quasistrings. + + * lib.c (cdr_f): New global variable. + (funcall1, funcall2, funcall3, funcall4): Fix unterminated + arguments in uw_throwf call by using uw_throw instead. + (do_or): New static function. + (orf): New function. + (obj_init): gc_protect and initialize cdr_f. + + * lib.h (cdr_f, orf): Declared. + + * match.c (v_deffilter): Treat the table as forms to be evaluated which + must reduce to strings, rather than literal strings. + + * txr.1: Documented. + +2011-11-19 Kaz Kylheku <kaz@kylheku.com> + * parser.y (yybadtoken): Use ~a to print bad character rather than #\ notation. @@ -77,7 +77,7 @@ val null_string; val nil_string; val null_list; -val identity_f, equal_f, eql_f, eq_f, car_f; +val identity_f, equal_f, eql_f, eq_f, car_f, cdr_f; val prog_string; @@ -1535,7 +1535,7 @@ val funcall1(val fun, val arg) case N1: return fun->f.f.n1(arg); default: - uw_throwf(error_s, lit("funcall1: wrong number of arguments")); + uw_throw(error_s, lit("funcall1: wrong number of arguments")); } } @@ -1549,7 +1549,7 @@ val funcall2(val fun, val arg1, val arg2) case N2: return fun->f.f.n2(arg1, arg2); default: - uw_throwf(error_s, lit("funcall2: wrong number of arguments")); + uw_throw(error_s, lit("funcall2: wrong number of arguments")); } } @@ -1563,7 +1563,7 @@ val funcall3(val fun, val arg1, val arg2, val arg3) case N3: return fun->f.f.n3(arg1, arg2, arg3); default: - uw_throwf(error_s, lit("funcall3: wrong number of arguments")); + uw_throw(error_s, lit("funcall3: wrong number of arguments")); } } @@ -1577,7 +1577,7 @@ val funcall4(val fun, val arg1, val arg2, val arg3, val arg4) case N4: return fun->f.f.n4(arg1, arg2, arg3, arg4); default: - uw_throwf(error_s, lit("funcall4: wrong number of arguments")); + uw_throw(error_s, lit("funcall4: wrong number of arguments")); } } @@ -1730,6 +1730,34 @@ val swap_12_21(val fun) return func_f2(fun, do_swap_12_21); } +static val do_or(val fun1_list, val arg) +{ + for (; fun1_list; fun1_list = cdr(fun1_list)) + if (funcall1(car(fun1_list), arg)) + return t; + + return nil; +} + +val orf(val first_fun, ...) +{ + va_list vl; + list_collect_decl (out, iter); + + if (first_fun != nao) { + val next_fun; + va_start (vl, first_fun); + list_collect (iter, first_fun); + + while ((next_fun = va_arg(vl, val)) != nao) + list_collect (iter, next_fun); + + va_end (vl); + } + + return func_f1(out, do_or); +} + val vector(val alloc) { cnum alloc_plus = c_num(alloc) + 2; @@ -2401,7 +2429,7 @@ static void obj_init(void) protect(&packages, &system_package, &keyword_package, &user_package, &null_string, &nil_string, - &null_list, &equal_f, &eq_f, &eql_f, &car_f, + &null_list, &equal_f, &eq_f, &eql_f, &car_f, &cdr_f, &identity_f, &prog_string, &env_list, (val *) 0); @@ -2513,6 +2541,7 @@ static void obj_init(void) eql_f = func_n2(eql); identity_f = func_n1(identity); car_f = func_n1(car); + cdr_f = func_n1(cdr); prog_string = string(progname); } @@ -261,7 +261,7 @@ extern val nothrow_k, args_k; extern val null_string; extern val null_list; /* (nil) */ -extern val identity_f, equal_f, eq_f, car_f; +extern val identity_f, equal_f, eq_f, car_f, cdr_f; extern const wchar_t *progname; extern val prog_string; @@ -399,6 +399,7 @@ val curry_123_23(val fun3, val arg1); val curry_1234_34(val fun3, val arg1, val arg2); val chain(val first_fun, ...); val andf(val first_fun, ...); +val orf(val first_fun, ...); val swap_12_21(val fun); val vector(val alloc); val vec_get_fill(val vec); @@ -2899,18 +2899,37 @@ static val v_deffilter(match_files_ctx *c) sem_error(specline, lit("deffilter: ~a is not a symbol"), first(first_spec), nao); - if (!all_satisfy(table, andf(func_n1(listp), - chain(func_n1(length), - curry_12_1(func_n2(ge), two), nao), - chain(func_n1(rest), - curry_123_1(func_n3(all_satisfy), - func_n1(stringp), nil), nao), - nao), - nil)) + if (!all_satisfy(table, func_n1(listp), nil)) + sem_error(specline, + lit("deffilter arguments must be lists"), + nao); + + { + val table_evaled = mapcar(curry_12_2(func_n2(mapcar), + chain(curry_123_2(func_n3(eval_form), + specline, c->bindings), + cdr_f, + nao)), + table); + + if (!all_satisfy(table_evaled, andf(func_n1(listp), + chain(func_n1(length), + curry_12_1(func_n2(ge), two), nao), + chain(func_n1(rest), + curry_123_1(func_n3(all_satisfy), + func_n1(stringp), + nil), + nao), + nao), + nil)) sem_error(specline, lit("deffilter arguments must be lists of at least two strings"), nao); - register_filter(sym, table); + + register_filter(sym, table_evaled); + } + + /* TODO: warn about replaced filter. */ return next_spec_k; } @@ -3564,9 +3564,10 @@ This directive's syntax is illustrated in this example: The deffilter symbol must be followed by the name of the filter to be defined, -followed by tuples of strings. Each tuple specifies one or more texts -which are mapped to a replacement text. For instance, the following specifies -a telephone keypad mapping from upper case letters to digits. +followed by tuples of forms which evaluate to strings. Each tuple specifies one +or more texts which are mapped to a replacement text. For instance, the +following specifies a telephone keypad mapping from upper case letters to +digits. Quasiliterals may be used. @(deffilter alpha_to_phone ("E" "0") ("J" "N" "Q" "1") @@ -3579,6 +3580,8 @@ a telephone keypad mapping from upper case letters to digits. ("L" "O" "P" "8") ("G" "H" "Z" "9")) + @(deffilter foo (`@a` `@b`) ("c" `->@d`)) + Filtering works using a longest match algorithm. The input is scanned from left to right, and the longest piece of text is identified at every character position which matches a string on the left hand side, and that text is |