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
During trial mode we might call `advance` to find a synchronization
point. If any of the bits touched by that fall into a gap, this can
trigger a `MissingData` exception.

In this patch we emit an additional `try`/`catch` block around the
`advance` if we search for a lookahead in `Try` mode. We can then
recover from `MissingData` by jumping to the next non-gap block in the
input.

Closes #1231.
  • Loading branch information
bbannier committed Jul 7, 2022
1 parent 5a95a18 commit 7c18597
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
28 changes: 27 additions & 1 deletion spicy/toolchain/src/compiler/codegen/parser-builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -891,10 +891,35 @@ struct ProductionVisitor
pushBuilder(builder()->addWhile(ms, builder::bool_(true)), [&]() {
builder()->addLocal(ID("rc"), hilti::type::SignedInteger(32));

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

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

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

// 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 ) {
popBuilder(); // body.
}

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

// No match, try again.
Expand Down Expand Up @@ -1059,6 +1084,7 @@ struct ProductionVisitor
}

state().printDebug(builder());

getLookAhead(*tokens, p->symbol(), p->location(), LiteralMode::Search);
validateSearchResult();
}
Expand All @@ -1070,7 +1096,7 @@ struct ProductionVisitor
void syncProductionNext(const Production& p) {
// We wrap lookahead search in a loop so we can advance manually should it get stuck
// at the same input position. This can happen if we end up synchronizing on an
// input token which matches something neear the start of the list element type, but
// input token which matches something near the start of the list element type, but
// is followed by other unexpected data. Without loop we would end up
// resynchronizing at the same input position again.
auto search_start = builder::local("search_start", state().cur);
Expand Down
4 changes: 2 additions & 2 deletions tests/Baseline/spicy.tools.spicy-driver-batch-gap/output
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error for ID id1: data is missing (<...>/spicy-driver-batch-gap.spicy:13:5)
error for ID id1: failed to synchronize: data is missing (<...>/spicy-driver-batch-gap.spicy:13:5)
[$data=[b"A", b"B"]]
[$data=[b"a", b"b"]]
[$data=[b"C", b"D"]]
[$data=[b"c", b"d"]]
error for ID id2: data is missing (<...>/spicy-driver-batch-gap.spicy:13:5)
error for ID id2: failed to synchronize: data is missing (<...>/spicy-driver-batch-gap.spicy:13:5)
[$data=[b"E", b"F"]]
[$data=[b"e", b"f"]]

0 comments on commit 7c18597

Please sign in to comment.