Skip to content

Commit

Permalink
Add special handling for potential advance failure in trial mode.
Browse files Browse the repository at this point in the history
In 7c18597 for #1231 we added code to
handle advance failures in trial mode when synchronizing on regexps, but
missed adding the same support for literals. This patch adds that
missing part.

Closes #1464.

(cherry picked from commit 30903c8)
  • Loading branch information
bbannier committed Jun 26, 2023
1 parent 2f59780 commit 1daed23
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 6 deletions.
42 changes: 36 additions & 6 deletions spicy/toolchain/src/compiler/codegen/parser-builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ struct ProductionVisitor
// block if we are in search mode and attempt to recover.
if ( mode == LiteralMode::Search ) {
auto [body, try_] = builder()->addTry();
pushBuilder(body);

pushBuilder(try_.addCatch(builder::parameter(ID("e"), builder::typeByID("hilti::MissingData"))),
[&]() {
// `advance` has failed, retry at the next non-gap block.
Expand All @@ -972,16 +972,17 @@ struct ProductionVisitor
// Continue incremental matching.
builder()->addContinue();
});

pushBuilder(body);
}

// Potentially bracketed `advance`.
builder()->addAssign(builder::tuple({builder::id("rc"), builder::id("ncur")}),
builder::memberCall(builder::id("ms"), "advance", {builder::id("ncur")}),
location);

if ( mode == LiteralMode::Search ) {
if ( mode == LiteralMode::Search )
popBuilder(); // body.
}

auto switch_ = builder()->addSwitch(builder::id("rc"), location);

Expand Down Expand Up @@ -1020,7 +1021,32 @@ struct ProductionVisitor
auto pstate = pb->state();
pstate.literal_mode = mode;
pushState(std::move(pstate));

// Since `advance` can trigger recoverable errors when
// hitting a gap, bracket the call to it in a `try`/`catch`
// block if we are in search mode and attempt to recover.
if ( mode == LiteralMode::Search ) {
auto [body, try_] = builder()->addTry();

pushBuilder(try_.addCatch(builder::parameter(ID("e"), builder::typeByID("hilti::MissingData"))),
[&]() {
// `advance` has failed, retry at the next non-gap block.
pb->advanceToNextData();

// // FIXME(bbannier):
// // We operate on `ncur` while `advanceToNextData`
// // updates `cur`; copy its result over.
// builder()->addAssign(ID("ncur"), state().cur);

// Continue incremental matching.
builder()->addContinue();
});

pushBuilder(body);
}

auto match = pb->parseLiteral(p, {});

popState();

if ( first_token ) {
Expand Down Expand Up @@ -1049,6 +1075,10 @@ struct ProductionVisitor
true_->addAssign(state().lahead, builder::integer(p.tokenID()));
true_->addAssign(state().lahead_end, builder::id("i"));
}

// Potentially bracketed `advance`.
if ( mode == LiteralMode::Search )
popBuilder(); // body.
};
};

Expand Down Expand Up @@ -1297,9 +1327,9 @@ struct ProductionVisitor
b->addBreak();
};

// The container element type creating this counter was marked `&synchronize`. Allow any container element to
// fail parsing and be skipped. This means that if `n` elements where requested and one element fails to parse,
// we will return `n-1` elements.
// The container element type creating this counter was marked `&synchronize`. Allow any container element
// to fail parsing and be skipped. This means that if `n` elements where requested and one element fails to
// parse, we will return `n-1` elements.
if ( auto f = p.body().meta().field(); f && AttributeSet::find(f->attributes(), "&synchronize") ) {
auto try_ = builder()->addTry();
pushBuilder(try_.first, [&]() { parse(); });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
Confirming with state: [$xs=[]]
[$xs=[[$a=b"A"]]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
Confirming with state: [$xs=[]]
[$xs=[[$a=b"A"]]]
44 changes: 44 additions & 0 deletions tests/spicy/types/unit/synchronize-failure-in-trial-mode.spicy
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# @TEST-DOC: Validates that advance errors in trial mode are handled properly. Regression test for #1231 and #1464.

# @TEST-EXEC: spicy-driver -d %INPUT -F test.dat >output 2>&1
# @TEST-EXEC: btest-diff output

module foo;

type X = unit {
a: b"A"; # Use literal for lookahead.
};

public type Foo = unit {
%port = 80/tcp;

xs: (X &synchronize)[];

on %synced { print "Confirming with state: %s" % self; confirm; }
on %done { print self; }
};

# @TEST-START-NEXT
module foo;

type X = unit {
a: /A/; # Use regexp for lookahead.
};

public type Foo = unit {
%port = 80/tcp;

xs: (X &synchronize)[];

on %synced { print "Confirming with state: %s" % self; confirm; }
on %done { print self; }
};

# @TEST-START-FILE test.dat
!spicy-batch v2
@begin-flow id1 stream 80/tcp
@gap id1 1024
@data id1 1
A
@end-flow id1
# @TEST-END-FILE

0 comments on commit 1daed23

Please sign in to comment.