summaryrefslogtreecommitdiffstats
path: root/match.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-09-28 08:19:58 -0700
committerKaz Kylheku <kaz@kylheku.com>2011-09-28 08:19:58 -0700
commit88a0ca81d753a6393b06fdabb984aeff48dcaa3b (patch)
tree1f901fe70fd43c3abe633c88866042463b308b1f /match.c
parentea7e91958c74d51ce05245243715dda42715e6ab (diff)
downloadtxr-88a0ca81d753a6393b06fdabb984aeff48dcaa3b.tar.gz
txr-88a0ca81d753a6393b06fdabb984aeff48dcaa3b.tar.bz2
txr-88a0ca81d753a6393b06fdabb984aeff48dcaa3b.zip
* match.c (match_line): Logic restructured to allow for
regex variables which also have nested variables. Previously this code was assuming that the cases were mutually exclusive, and the parser happened to work that way. Also, added support for a "double var" match which occurs when an unbound variable is followed by a regex variable. This case should be allowed because it makes sense. It's similar to a variable followed by a regex, except that the regex is also a variable binding. * parser.y (o_elems_transform): New function. (o_elems_opt, o_elems_opt2, quasilit): Transform o_elems with new function. This is needed because subst_vars doesn't deal with the nested var syntax for consecutive variables. (var): New syntax case '{' IDENT exprs '}' elem. This allows consecutive variables to be nested in all cases.
Diffstat (limited to 'match.c')
-rw-r--r--match.c111
1 files changed, 76 insertions, 35 deletions
diff --git a/match.c b/match.c
index a00064ca..01d96bf5 100644
--- a/match.c
+++ b/match.c
@@ -305,6 +305,13 @@ static val match_line(val bindings, val specline, val dataline,
val modifier = fourth(elem);
val pair = assoc(bindings, sym); /* var exists already? */
+ if (gt(length(modifier), one)) {
+ sem_error(spec_lineno, lit("multiple modifiers on variable ~s"),
+ sym, nao);
+ }
+
+ modifier = car(modifier);
+
if (pair) {
/* If the variable already has a binding, we replace
it with its value, and treat it as a string match.
@@ -336,37 +343,41 @@ static val match_line(val bindings, val specline, val dataline,
specline = cons(cdr(pair), rest(specline));
}
continue;
- } else if (pat == nil) { /* match to end of line or with regex */
- if (gt(length(modifier), one)) {
- sem_error(spec_lineno, lit("multiple modifiers on variable ~s"),
- sym, nao);
+ } else if (consp(modifier)) { /* regex variable */
+ val past = match_regex(dataline, car(modifier), pos);
+ if (nullp(past)) {
+ LOG_MISMATCH("var positive regex");
+ return nil;
}
-
- modifier = car(modifier);
-
- if (consp(modifier)) {
- val past = match_regex(dataline, car(modifier), pos);
- if (nullp(past)) {
- LOG_MISMATCH("var positive regex");
- return nil;
- }
- LOG_MATCH("var positive regex", past);
- bindings = acons_new(bindings, sym, sub_str(dataline, pos, past));
- pos = past;
- } else if (nump(modifier)) {
- val past = plus(pos, modifier);
- if (length_str_lt(dataline, past) || lt(past, pos))
- {
- LOG_MISMATCH("count based var");
- return nil;
- }
- LOG_MATCH("count based var", past);
- bindings = acons_new(bindings, sym, trim_str(sub_str(dataline, pos, past)));
- pos = past;
- } else {
- bindings = acons_new(bindings, sym, sub_str(dataline, pos, nil));
- pos = length_str(dataline);
+ LOG_MATCH("var positive regex", past);
+ bindings = acons_new(bindings, sym, sub_str(dataline, pos, past));
+ pos = past;
+ /* This may have another variable attached */
+ if (pat) {
+ specline = cons(pat, rest(specline));
+ continue;
}
+ } else if (nump(modifier)) { /* fixed field */
+ val past = plus(pos, modifier);
+ if (length_str_lt(dataline, past) || lt(past, pos))
+ {
+ LOG_MISMATCH("count based var");
+ return nil;
+ }
+ LOG_MATCH("count based var", past);
+ bindings = acons_new(bindings, sym, trim_str(sub_str(dataline, pos, past)));
+ pos = past;
+ /* This may have another variable attached */
+ if (pat) {
+ specline = cons(pat, rest(specline));
+ continue;
+ }
+ } else if (modifier) {
+ sem_error(spec_lineno, lit("invalid modifier ~s on variable ~s"),
+ modifier, sym, nao);
+ } else if (pat == nil) { /* no modifier, no elem -> to end of line */
+ bindings = acons_new(bindings, sym, sub_str(dataline, pos, nil));
+ pos = length_str(dataline);
} else if (type(pat) == STR) {
val find = search_str(dataline, pat, pos, modifier);
if (!find) {
@@ -388,26 +399,55 @@ static val match_line(val bindings, val specline, val dataline,
bindings = acons_new(bindings, sym, sub_str(dataline, pos, fpos));
pos = plus(fpos, flen);
} else if (consp(pat) && first(pat) == var_s) {
- /* Unbound var followed by var: the following one must be bound. */
+ /* Unbound var followed by var: the following one must either
+ be bound, or must specify a regex. */
val second_sym = second(pat);
val next_pat = third(pat);
+ val next_modifier = fourth(pat);
val pair = assoc(bindings, second_sym); /* var exists already? */
- if (!pair)
- sem_error(spec_lineno, lit("consecutive unbound variables"), nao);
+ if (gt(length(next_modifier), one)) {
+ sem_error(spec_lineno, lit("multiple modifiers on variable ~s"),
+ second_sym, nao);
+ }
+
+ next_modifier = car(next_modifier);
+ if (!pair && consp(next_modifier)) {
+ val find = search_regex(dataline, first(next_modifier), pos, modifier);
+ val fpos = car(find);
+ val flen = cdr(find);
+
+ if (!find) {
+ LOG_MISMATCH("double var regex");
+ return nil;
+ }
+
+ /* Text from here to start of regex match goes to this
+ variable. */
+ bindings = acons_new(bindings, sym, sub_str(dataline, pos, fpos));
+ /* Text from start of regex match to end goes to the
+ second variable */
+ bindings = acons_new(bindings, second_sym, sub_str(dataline, fpos, plus(fpos, flen)));
+ LOG_MATCH("double var regex (first var)", fpos);
+ pos = fpos;
+ LOG_MATCH("double var regex (second var)", plus(fpos, flen));
+ pos = plus(fpos, flen);
+ specline = cons(next_pat, rest(specline));
+ continue;
+ } else if (!pair) {
+ sem_error(spec_lineno, lit("consecutive unbound variables"), nao);
+ } else {
/* Re-generate a new spec with an edited version of
the element we just processed, and repeat. */
- {
val new_elem = list(var_s, sym, cdr(pair), modifier, nao);
if (next_pat)
specline = cons(new_elem, cons(next_pat, rest(specline)));
else
specline = cons(new_elem, rest(specline));
+ continue;
}
-
- continue;
} else if (consp(pat) && (consp(first(pat)) || stringp(first(pat)))) {
cons_bind (find, len, search_str(dataline, pat, pos, modifier));
if (!find) {
@@ -608,6 +648,7 @@ static val subst_vars(val spec, val bindings, val filter)
spec = cons(filter_string(filter, cdr(pair)), rest(spec));
continue;
}
+ /* TODO: handle unbound variable */
} else if (first(elem) == quasi_s) {
val nested = subst_vars(rest(elem), bindings, filter);
list_collect_append(iter, nested);