From 3f116ba6a398244dfc8b202dfc4087b92bbaabb4 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 21 Oct 2011 20:37:03 -0400 Subject: * match.c (v_collect): Regression bugfix. Make it work like the comment says: until/last clause has visibility to uncollated bindings from collect. * txr.1: Document behavior. --- ChangeLog | 8 ++++++++ match.c | 22 ++++++++++++++++++++++ txr.1 | 29 +++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9abf2bd2..42bf46af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-10-21 Kaz Kylheku + + * match.c (v_collect): Regression bugfix. Make it work like the comment + says: until/last clause has visibility to uncollated bindings from + collect. + + * txr.1: Document behavior. + 2011-10-21 Kaz Kylheku * match.c (v_collect): Regression bugfix. Make it work like the comment diff --git a/match.c b/match.c index 894f6d73..174c2a1c 100644 --- a/match.c +++ b/match.c @@ -776,6 +776,17 @@ next_coll: c.bindings = nappend2(last_bindings, c.bindings); } + /* If nothing was collected, but vars were specified, + then bind empty lists for the vars. */ + if (!bindings_coll && vars) { + for (iter = vars; iter; iter = cdr(iter)) { + val sym = car(car(iter)); + val exists = assoc(c.bindings, sym); + if (!exists) + c.bindings = acons(c.bindings, sym, nil); + } + } + *cout = c; return next_spec_k; } @@ -2043,6 +2054,17 @@ next_collect: c.bindings = nappend2(last_bindings, c.bindings); } + /* If nothing was collected, but vars were specified, + then bind empty lists for the vars. */ + if (!bindings_coll && vars) { + for (iter = vars; iter; iter = cdr(iter)) { + val sym = car(car(iter)); + val exists = assoc(c.bindings, sym); + if (!exists) + c.bindings = acons(c.bindings, sym, nil); + } + } + *cout = c; return next_spec_k; } diff --git a/txr.1 b/txr.1 index 9b47039c..a7941a93 100644 --- a/txr.1 +++ b/txr.1 @@ -1753,9 +1753,11 @@ There is one more keyword, :vars, discussed in the following section. Normally, any variable for which a new binding occurs in a collect is collected. A collect clause may be sloppy: it can neglect to collect some variables on some iterations, or bind some variables which behave like -local temporaries, but end up collated into lists. +local temporaries, but end up collated into lists. Another issue is that +the collect clause might not match anything at all, and then none of +the variables are bound. -The :vars keyword allows the query writer to tame the collect body. +The :vars keyword allows the query writer to add discipline the collect body. The argument to :vars is a list of variable specs. A variable spec is either a symbol, or a ( ) pair, where the expression specifies a @@ -1769,11 +1771,17 @@ Furthermore, for any variable which is not specified with a default value, the collect body, whenever it matches successfully, must bind that variable. If it neglects to bind the variable, an exception of type query_error is thrown. -For any variable which has a default value, if the collect body neglects to -bind that variable, the behavior is as if the collect did bind that variable to that default value. +For any variable which does have a default value, if the collect body neglects +to bind that variable, the behavior is as if the collect did bind that variable +to that default value. The default values are expressions, and so can be quasiliterals. +Lastly, if in the event that the collect does not match anything, the variables +specified in vars (whether or not they have a default value) are all bound to +empty lists. (These bindings are established after the processing of the +until/last clause, if present.) + Example: @(collect :vars (a b (c "foo"))) @@ -1794,6 +1802,19 @@ in the variable list. Furthermore, because there is no binding for c in the body, a binding is created with the value "foo", exactly as if c matched such a piece of text. +In the following example, the assumption is that THIS NEVER MATCHES +is not found anywhere in the input but the line THIS DOES MATCH is +found and has a successor which is bound to a. Because the body did not +match, the :vars a and b should be bound to empty lists. But a is bound +by the last clause to some text, so this takes precedence. Only b is bound to a +an empty list. + + @(collect :vars (a b) + THIS NEVER MATCHES + @(last) + THIS DOES MATCH + @a + @(end) .SS The Coll Directive -- cgit v1.2.3