diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | filter.c | 4 | ||||
-rw-r--r-- | lib.c | 20 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | match.c | 14 | ||||
-rw-r--r-- | txr.1 | 32 |
6 files changed, 70 insertions, 20 deletions
@@ -1,5 +1,23 @@ 2011-10-25 Kaz Kylheku <kaz@kylheku.com> + Shorthand for filters which map multiple texts to a common + replacement text. + + * filter.c (build_filter_from_list): Allow tuples to denote + multiple keys mapping to the same value. + + * lib.c (do_curry_123_2, do_curry_123_1): New static functions. + (curry_123_2, curry_123_1): New functions. + + * lib.h (curry_123_2, curry_123_1): New functions declared. + + * match.c (v_deffilter): Allow tuples of strings rather than + just pairs. + + * txr.1: Updated. + +2011-10-25 Kaz Kylheku <kaz@kylheku.com> + * parser.y: Remove mention of nonexistent terminal \\ from %right associativity clause. @@ -184,8 +184,8 @@ static val build_filter_from_list(val list) val iter; for (iter = list; iter; iter = cdr(iter)) { - val pair = car(iter); - trie_add(trie, first(pair), second(pair)); + val tuple = reverse(car(iter)); + mapcar(curry_123_2(func_n3(trie_add), trie, first(tuple)), rest(tuple)); } trie_compress(&trie); @@ -1598,6 +1598,16 @@ val curry_12_1(val fun2, val arg2) return func_f1(cons(fun2, arg2), do_curry_12_1); } +static val do_curry_123_3(val fcons, val arg3) +{ + return funcall3(car(fcons), car(cdr(fcons)), cdr(cdr(fcons)), arg3); +} + +val curry_123_3(val fun3, val arg1, val arg2) +{ + return func_f1(cons(fun3, cons(arg1, arg2)), do_curry_123_3); +} + static val do_curry_123_2(val fcons, val arg2) { return funcall3(car(fcons), car(cdr(fcons)), arg2, cdr(cdr(fcons))); @@ -1608,6 +1618,16 @@ val curry_123_2(val fun3, val arg1, val arg3) return func_f1(cons(fun3, cons(arg1, arg3)), do_curry_123_2); } +static val do_curry_123_1(val fcons, val arg1) +{ + return funcall3(car(fcons), arg1, car(cdr(fcons)), cdr(cdr(fcons))); +} + +val curry_123_1(val fun3, val arg2, val arg3) +{ + return func_f1(cons(fun3, cons(arg2, arg3)), do_curry_123_1); +} + static val do_curry_123_23(val fcons, val arg2, val arg3) { return funcall3(car(fcons), cdr(fcons), arg2, arg3); @@ -390,7 +390,9 @@ val reduce_left(val fun, val list, val init, val key); Other variations follow by analogy. */ val curry_12_2(val fun2, val arg); val curry_12_1(val fun2, val arg2); +val curry_123_3(val fun3, val arg1, val arg2); val curry_123_2(val fun3, val arg1, val arg3); +val curry_123_1(val fun3, val arg2, val arg3); val curry_123_23(val fun3, val arg1); val curry_1234_34(val fun3, val arg1, val arg2); val chain(val first_fun, ...); @@ -2555,18 +2555,14 @@ static val v_deffilter(match_files_ctx c, match_files_ctx *cout) if (!all_satisfy(table, andf(func_n1(listp), chain(func_n1(length), - curry_12_2(func_n2(eq), two), - nao), - chain(func_n1(first), - func_n1(stringp), - nao), - chain(func_n1(second), - func_n1(stringp), - nao), + 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(spec_linenum, - lit("deffilter arguments must be string pairs"), + lit("deffilter arguments must be lists of at least two strings"), nao); register_filter(sym, table); /* TODO: warn about replaced filter. */ @@ -3124,23 +3124,37 @@ 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 pairs of strings. Each pair specifies a piece of text to be -filtered from the left hand side to the right hand side. +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. + + @(deffilter alpha_to_phone ("E" "0") + ("J" "N" "Q" "1") + ("R" "W" "X" "2") + ("D" "S" "Y" "3") + ("F" "T" "4") + ("A" "M" "5") + ("C" "I" "V" "6") + ("B" "K" "U" "7") + ("L" "O" "P" "8") + ("G" "H" "Z" "9")) 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 -replaced with the right hand string. +replaced with its associated replacement text. The scanning then continues +at the first character after the matched text. If none of the strings matches at a given character position, then that -character is passed through untranslated, and the scan continues at the next -character in the input. - -If a filter definition accidentally -contains two or more repetitions of the same left hand string with different -right hand translations, the later ones take precedence. No warning is issued. +character is passed through the filter untranslated, and the scan continues at +the next character in the input. +Filtering is not in-place but rather instantiates a new text, and so +replacement text is not re-scanned for more replacements. +If a filter definition accidentally contains two or more repetitions of the +same left hand string with different right hand translations, the later ones +take precedence. No warning is issued. .SH EXCEPTIONS |