From acb0fc7a846d1fd1799613351f4048b9be5ce89a Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 20 Feb 2017 21:01:23 -0800 Subject: bugfix: data stream escape in accept transfers. This fixes a bug in the same category as the parent commit. The issue of concern here is that if an @(accept) control transfer terminates a @(next) directive, the data stream to which the @(next) directive switched escapes out of that scope. Example: @(block b) @(next :list '("line")) @(accept b) @(end) @var Here, var captures "line" because the stream set up by @(next) is carried by the @(accept) to the destination block, and then taken as the current data source going forward. The overwhelmingly preferrable behavior is for the accept to honor the input source controlling dynamic scope of the @(next) directive. When the control transfer crosses a @(next) boundary by terminating a next directive, the transfer's data must be replaced by the original data stream just prior the @(next). However, the bindings are carried through untouched. This is basically opposite to pattern function invocations. Pattern functions freely advance the data position in the same stream, but carefully control what bindings emerge. Whereas @(next) carefully scopes the input source, but freely allows bindings to emerge. The @(accept) control transfers must be in accord with these behaviors. And, in the existing case of @(trailer) which properly interacts with accept, the same holds. That directive allows bindings to escape but prevents the advancement of the input within the current stream. If it is terminated by @(accept), these hold. * match.c (v_next_impl): New static function, identical to previous v_next. (v_next): Reduced to wrapper around v_next_impl which intercepts @(accept) control transfers and fixes up their data position to match the position coming into the @(next). --- match.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/match.c b/match.c index 7f046fb0..1dafcbbe 100644 --- a/match.c +++ b/match.c @@ -2555,7 +2555,7 @@ static val v_accept_fail(match_files_ctx *c) return nil; } -static val v_next(match_files_ctx *c) +static val v_next_impl(match_files_ctx *c) { spec_bind (specline, first_spec, c->spec); @@ -2746,6 +2746,27 @@ static val v_next(match_files_ctx *c) } } +static val v_next(match_files_ctx *c) +{ + val result = nil; + + uw_simple_catch_begin; + + result = v_next_impl(c); + + uw_unwind { + uw_frame_t *ex = uw_current_exit_point(); + if (ex && ex->uw.type == UW_BLOCK && ex->bl.protocol == accept_s) { + set(vecref_l(ex->bl.result, one), cons(c->data, c->data_lineno)); + set(vecref_l(ex->bl.result, two), nil); + } + } + + uw_catch_end; + + return result; +} + static val v_parallel(match_files_ctx *c) { spec_bind (specline, first_spec, c->spec); -- cgit v1.2.3