summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-12-30 12:26:41 -0800
committerKaz Kylheku <kaz@kylheku.com>2011-12-30 12:26:41 -0800
commitac08d22c2b916fbd88c938569e0cd6af488b7a67 (patch)
tree845a929d332f67cc7ec6bd5196b3acf3d52f69b7
parent0b81b8b4c39b6c60cbbe8de5a6a785beb43c3dbb (diff)
downloadtxr-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--ChangeLog21
-rw-r--r--match.c31
-rw-r--r--match.h2
-rw-r--r--parser.l8
-rw-r--r--parser.y20
-rw-r--r--txr.112
6 files changed, 76 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 13c01dae..bab15280 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/match.c b/match.c
index e87b7496..044e1300 100644
--- a/match.c
+++ b/match.c
@@ -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)
diff --git a/match.h b/match.h
index 55deef7a..bb69a030 100644
--- a/match.h
+++ b/match.h
@@ -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);
diff --git a/parser.l b/parser.l
index c571691c..59e7767e 100644
--- a/parser.l
+++ b/parser.l
@@ -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;
}
diff --git a/parser.y b/parser.y
index 13dff805..c6e53276 100644
--- a/parser.y
+++ b/parser.y
@@ -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;
diff --git a/txr.1 b/txr.1
index 1b360ea8..8ba7afaf 100644
--- a/txr.1
+++ b/txr.1
@@ -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,