diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2011-12-30 12:26:41 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2011-12-30 12:26:41 -0800 |
commit | ac08d22c2b916fbd88c938569e0cd6af488b7a67 (patch) | |
tree | 845a929d332f67cc7ec6bd5196b3acf3d52f69b7 | |
parent | 0b81b8b4c39b6c60cbbe8de5a6a785beb43c3dbb (diff) | |
download | txr-ac08d22c2b916fbd88c938569e0cd6af488b7a67.tar.gz txr-ac08d22c2b916fbd88c938569e0cd6af488b7a67.tar.bz2 txr-ac08d22c2b916fbd88c938569e0cd6af488b7a67.zip |
* match.c (counter_k): New keyword symbol variable.
(do_output_line): Process new :counter argument of rep.
(do_output): Ditto, for repeat.
(syms_init): Intern new keyword symbol.
* match.h (counter_k): Declared.
* parser.l (REPEAT, REP): Lexical syntax changed to
allow arguments.
* parser.y (repeat_rep_helper): Takes extra argument, representing
the repeat/rep args. This is inserted into the second position
of the output list.
(repeat_clause, rep_elem): Extract repeat/rep arguments and
pass to repeat_rep_helper.
(yybadtoken): Do not put quotes around the word "number".
* txr.1: Updated.
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | match.c | 31 | ||||
-rw-r--r-- | match.h | 2 | ||||
-rw-r--r-- | parser.l | 8 | ||||
-rw-r--r-- | parser.y | 20 | ||||
-rw-r--r-- | txr.1 | 12 |
6 files changed, 76 insertions, 18 deletions
@@ -1,3 +1,24 @@ +2011-12-30 Kaz Kylheku <kaz@kylheku.com> + + * match.c (counter_k): New keyword symbol variable. + (do_output_line): Process new :counter argument of rep. + (do_output): Ditto, for repeat. + (syms_init): Intern new keyword symbol. + + * match.h (counter_k): Declared. + + * parser.l (REPEAT, REP): Lexical syntax changed to + allow arguments. + + * parser.y (repeat_rep_helper): Takes extra argument, representing + the repeat/rep args. This is inserted into the second position + of the output list. + (repeat_clause, rep_elem): Extract repeat/rep arguments and + pass to repeat_rep_helper. + (yybadtoken): Do not put quotes around the word "number". + + * txr.1: Updated. + 2011-12-29 Kaz Kylheku <kaz@kylheku.com> New functionality: mod and modlast directives in repeat and rep. @@ -58,7 +58,7 @@ val lines_k, chars_k; val text_s, choose_s, gather_s, do_s, mod_s, modlast_s; val longest_k, shortest_k, greedy_k; val vars_k, resolve_k; -val append_k, into_k, var_k, list_k, string_k, env_k; +val append_k, into_k, var_k, list_k, string_k, env_k, counter_k; val filter_s; @@ -1534,6 +1534,7 @@ static void do_output_line(val bindings, val specline, val filter, val out) put_string(out, str); } else if (directive == rep_s) { val clauses = cdr(elem); + val args = pop(&clauses); val main_clauses = pop(&clauses); val single_clauses = pop(&clauses); val first_clauses = pop(&clauses); @@ -1541,6 +1542,7 @@ static void do_output_line(val bindings, val specline, val filter, val out) val empty_clauses = pop(&clauses); val mod_clauses = pop(&clauses); val modlast_clauses = pop(&clauses); + val counter = getplist(args, counter_k); val bind_cp = extract_bindings(bindings, elem); val max_depth = reduce_left(func_n2(max2), bind_cp, zero, @@ -1548,18 +1550,30 @@ static void do_output_line(val bindings, val specline, val filter, val out) func_n1(robust_length), nao)); + if (counter && !bindable(counter)) + sem_error(elem, lit(":counter requires a bindable symbol, not ~s"), + counter, nao); + if (equal(max_depth, zero) && empty_clauses) { do_output_line(nappend2(bind_cp, bindings), empty_clauses, filter, out); } else if (equal(max_depth, one) && single_clauses) { val bind_a = nappend2(mapcar(func_n1(bind_car), bind_cp), bindings); do_output_line(bind_a, single_clauses, filter, out); } else if (!zerop(max_depth)) { + val counter_var = if2(counter, cons(counter, nil)); + val counter_bind = if2(counter, cons(counter_var, nil)); cnum i; for (i = 0; i < c_num(max_depth); i++) { val bind_a = nappend2(mapcar(func_n1(bind_car), bind_cp), bindings); val bind_d = mapcar(func_n1(bind_cdr), bind_cp); + if (counter) { + rplacd(counter_var, num_fast(i)); + rplacd(counter_bind, bind_a); + bind_a = counter_bind; + } + if (i == 0 && first_clauses) { do_output_line(bind_a, first_clauses, filter, out); } else if (i == c_num(max_depth) - 1 && @@ -1645,6 +1659,7 @@ static void do_output(val bindings, val specs, val filter, val out) if (sym == repeat_s) { val clauses = cdr(first_elem); + val args = pop(&clauses); val main_clauses = pop(&clauses); val single_clauses = pop(&clauses); val first_clauses = pop(&clauses); @@ -1652,6 +1667,7 @@ static void do_output(val bindings, val specs, val filter, val out) val empty_clauses = pop(&clauses); val mod_clauses = pop(&clauses); val modlast_clauses = pop(&clauses); + val counter = getplist(args, counter_k); val bind_cp = extract_bindings(bindings, first_elem); val max_depth = reduce_left(func_n2(max2), bind_cp, zero, @@ -1665,12 +1681,20 @@ static void do_output(val bindings, val specs, val filter, val out) val bind_a = nappend2(mapcar(func_n1(bind_car), bind_cp), bindings); do_output(bind_a, single_clauses, filter, out); } else if (!zerop(max_depth)) { + val counter_var = if2(counter, cons(counter, nil)); + val counter_bind = if2(counter, cons(counter_var, nil)); cnum i; for (i = 0; i < c_num(max_depth); i++) { val bind_a = nappend2(mapcar(func_n1(bind_car), bind_cp), bindings); val bind_d = mapcar(func_n1(bind_cdr), bind_cp); + if (counter) { + rplacd(counter_var, num_fast(i)); + rplacd(counter_bind, bind_a); + bind_a = counter_bind; + } + if (i == 0 && first_clauses) { do_output(bind_a, first_clauses, filter, out); } else if (i == c_num(max_depth) - 1 && @@ -3413,8 +3437,9 @@ static void syms_init(void) filter_s = intern(lit("filter"), user_package); noval_s = intern(lit("noval"), system_package); - mod_s = intern(lit("mod"), system_package); - modlast_s = intern(lit("modlast"), system_package); + mod_s = intern(lit("mod"), user_package); + modlast_s = intern(lit("modlast"), user_package); + counter_k = intern(lit("counter"), keyword_package); } static void dir_tables_init(void) @@ -24,7 +24,7 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -extern val text_s, choose_s, gather_s, do_s, mod_s, modlast_s; +extern val text_s, choose_s, gather_s, do_s, mod_s, modlast_s, counter_k; val format_field(val string_or_list, val modifier, val filter); val match_funcall(val name, val arg, val other_args); int extract(val spec, val filenames, val bindings); @@ -285,15 +285,15 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} return OUTPUT; } -<SPECIAL>\({WS}repeat{WS}\) { - yy_pop_state(); +<SPECIAL>\({WS}repeat/{ID_END} { + yy_push_state(NESTED); yylval.lineno = lineno; return REPEAT; } -<SPECIAL>\({WS}rep{WS}\) { - yy_pop_state(); +<SPECIAL>\({WS}rep/{ID_END} { + yy_push_state(NESTED); yylval.lineno = lineno; return REP; } @@ -46,7 +46,7 @@ int yylex(void); void yyerror(const char *); -static val repeat_rep_helper(val sym, val main, val parts); +static val repeat_rep_helper(val sym, val args, val main, val parts); static val o_elems_transform(val output_form); static val define_transform(val define_form); static val lit_char_helper(val litchars); @@ -468,10 +468,11 @@ out_clause : repeat_clause { $$ = cons($1, nil); } yyerror("match clause in output"); } ; -repeat_clause : REPEAT newl +repeat_clause : REPEAT exprs_opt ')' newl out_clauses_opt repeat_parts_opt - END newl { $$ = repeat_rep_helper(repeat_s, $3, $4); + END newl { $$ = repeat_rep_helper(repeat_s, + $2, $5, $6); rl($$, num($1)); } | REPEAT newl error { $$ = nil; @@ -539,10 +540,11 @@ o_elem : TEXT { $$ = string_own($1); | rep_elem { $$ = $1; } ; -rep_elem : REP o_elems_opt +rep_elem : REP exprs_opt ')' o_elems_opt rep_parts_opt END { $$ = repeat_rep_helper(rep_s, - o_elems_transform($2), - $3); + $2, + o_elems_transform($4), + $5); rl($$, num($1)); } | REP error { $$ = nil; yybadtoken(yychar, lit("rep clause")); } @@ -804,7 +806,7 @@ litchars : LITCHAR { $$ = cons(chr($1), nil); } %% -static val repeat_rep_helper(val sym, val main, val parts) +static val repeat_rep_helper(val sym, val args, val main, val parts) { val single_parts = nil; val first_parts = nil; @@ -835,7 +837,7 @@ static val repeat_rep_helper(val sym, val main, val parts) abort(); } - return list(sym, main, single_parts, first_parts, + return list(sym, args, main, single_parts, first_parts, last_parts, empty_parts, nreverse(mod_parts), nreverse(modlast_parts), nao); } @@ -1029,7 +1031,7 @@ void yybadtoken(int tok, val context) case TRY: problem = lit("\"try\""); break; case CATCH: problem = lit("\"catch\""); break; case FINALLY: problem = lit("\"finally\""); break; - case NUMBER: problem = lit("\"number\""); break; + case NUMBER: problem = lit("number"); break; case REGCHAR: problem = lit("regular expression character"); break; case LITCHAR: problem = lit("string literal character"); break; case METAPAR: problem = lit("@("); break; @@ -3295,9 +3295,11 @@ like this: @(end) Repeat has four types of special clauses, any of which may be -specified with empty contents, or omitted entirely. They are explained +specified with empty contents, or omitted entirely. They are described below. +Repeat takes arguments, also described below. + All of the material in the main clause and optional clauses is examined for the presence of variables. If none of the variables hold lists which contain at least one item, then no output is performed, @@ -3381,6 +3383,14 @@ are none, or none of them activate, then @(last) is considered. If none of those clauses are present or apply, then the repetition is processed using the main clause. +Repeat supports an optional keyword argument: + + @(repeat [:counter <symbol>]) + +This designates a symbol which will behave as an integer variable over the +scope of the clauses inside the repeat. The variable provides access to the +reptition count, starting at zero, incrementing with each repetition. + .SS Nested Repeats If a repeat clause encloses variables which holds multidimensional lists, |