summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--match.c34
-rw-r--r--txr.112
3 files changed, 45 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 56a83cbb..917475c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2012-03-30 Kaz Kylheku <kaz@kylheku.com>
+ * match.c (h_var): Disallow the variable named by the symbol t
+ by throwing an exception. Allow nil, but wherever nil occurs,
+ do not produce a binding.
+
+ * txr.1: State the restrictions against using t in the section
+ on Variables and also describe the nil ignore feature.
+
+2012-03-30 Kaz Kylheku <kaz@kylheku.com>
+
* txr.1: Correction: backtracking does NOT take place into a block
which completed.
diff --git a/match.c b/match.c
index e2128111..36b5c9a2 100644
--- a/match.c
+++ b/match.c
@@ -463,8 +463,11 @@ static val h_var(match_line_ctx *c)
val pat = third(elem);
val modifiers = fourth(elem);
val modifier = first(modifiers);
- val pair = assoc(sym, c->bindings); /* var exists already? */
+ val pair = if2(sym, assoc(sym, c->bindings)); /* exists? */
+ if (sym == t)
+ sem_error(elem, lit("t is not a bindable symbol"), nao);
+
if (gt(length_list(modifiers), one)) {
sem_error(elem, lit("multiple modifiers on variable ~s"),
sym, nao);
@@ -511,7 +514,8 @@ static val h_var(match_line_ctx *c)
}
LOG_MATCH("var spanning form", new_pos);
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, new_pos), new_bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, new_pos), new_bindings);
c->pos = new_pos;
/* This may have another variable attached */
if (pat) {
@@ -526,7 +530,8 @@ static val h_var(match_line_ctx *c)
return nil;
}
LOG_MATCH("count based var", past);
- c->bindings = acons(sym, trim_str(sub_str(c->dataline, c->pos, past)), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, trim_str(sub_str(c->dataline, c->pos, past)), c->bindings);
c->pos = past;
/* This may have another variable attached */
if (pat) {
@@ -537,7 +542,8 @@ static val h_var(match_line_ctx *c)
sem_error(elem, lit("invalid modifier ~s on variable ~s"),
modifier, sym, nao);
} else if (pat == nil) { /* no modifier, no elem -> to end of line */
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, nil), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, nil), c->bindings);
c->pos = length_str(c->dataline);
} else if (type(pat) == STR) {
val find = search_str(c->dataline, pat, c->pos, modifier);
@@ -546,7 +552,8 @@ static val h_var(match_line_ctx *c)
return nil;
}
LOG_MATCH("var delimiting string", find);
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, find), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, find), c->bindings);
c->pos = plus(find, length_str(pat));
} else if (consp(pat) && first(pat) != var_s) {
val find = search_form(c, pat, modifier);
@@ -557,7 +564,8 @@ static val h_var(match_line_ctx *c)
return nil;
}
LOG_MATCH("var delimiting form", fpos);
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, fpos), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, fpos), c->bindings);
c->pos = if3(flen == t, t, plus(fpos, flen));
} else if (consp(pat)) {
/* Unbound var followed by var: the following one must either
@@ -566,7 +574,7 @@ static val h_var(match_line_ctx *c)
val next_pat = third(pat);
val next_modifiers = fourth(pat);
val next_modifier = first(fourth(pat));
- val pair = assoc(second_sym, c->bindings); /* var exists already? */
+ val pair = if2(second_sym, assoc(second_sym, c->bindings)); /* exists? */
if (gt(length_list(next_modifiers), one)) {
sem_error(elem, lit("multiple modifiers on variable ~s"),
@@ -585,10 +593,15 @@ static val h_var(match_line_ctx *c)
/* Text from here to start of regex match goes to this
variable. */
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, fpos), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, fpos),
+ c->bindings);
/* Text from start of regex match to end goes to the
second variable */
- c->bindings = acons(second_sym, sub_str(c->dataline, fpos, plus(fpos, flen)), c->bindings);
+ if (second_sym)
+ c->bindings = acons(second_sym,
+ sub_str(c->dataline, fpos, plus(fpos, flen)),
+ c->bindings);
LOG_MATCH("double var regex (first var)", fpos);
c->pos = fpos;
LOG_MATCH("double var regex (second var)", plus(fpos, flen));
@@ -616,7 +629,8 @@ static val h_var(match_line_ctx *c)
LOG_MISMATCH("string");
return nil;
}
- c->bindings = acons(sym, sub_str(c->dataline, c->pos, find), c->bindings);
+ if (sym)
+ c->bindings = acons(sym, sub_str(c->dataline, c->pos, find), c->bindings);
c->pos = plus(find, len);
} else {
sem_error(elem, lit("variable followed by invalid element"), nao);
diff --git a/txr.1 b/txr.1
index b021cdd7..533bc464 100644
--- a/txr.1
+++ b/txr.1
@@ -572,6 +572,11 @@ The forms with an * indicate a long match, see Longest Match below.
The last two forms with the embedded regexp /RE/ or number have special
semantics, see Positive Match below.
+The identifier t cannot be used as a name; it is a reserved symbol which
+denotes the value true. An attempt to use the variable @t will result
+in an exception. The symbol nil can be used as a variable name,
+but it has special semantics, described in a section below.
+
When the @NAME form is used, the name itself may consist of any combination of
one or more letters, numbers, and underscores. It may not look like a number,
so that for instance 123 is not a valid name, but 12A is valid. Case is
@@ -820,6 +825,13 @@ This syntax is processed without consideration of what other
syntax follows. A positive match may be directly followed by an unbound
variable.
+.SS Symbol nil as a Variable
+
+If the symbol nil is used as a variable, it behaves like a variable which
+has no binding. Furthermore, no binding is created. @nil allows the
+variable matching syntax to be used to skip material, in ways different
+from and complementary to @(skip).
+
.SS Regular Expressions
Regular expressions are a language for specifying sets of character strings.