Skip to content

Commit

Permalink
Fine-tune bytes literal parsing further.
Browse files Browse the repository at this point in the history
This now optimizes the generated code for parsing a `bytes` literal
based on what we're going to use it for, or not (require literal vs.
look-ahead vs skip).

The standard case of a parsing an expected literal now looks like
this:

```
    # Begin parsing production: Ctor: b1  -> b"abc" (const bytes)
    (*self).b1 = spicy_rt::expectBytesLiteral(__data, __cur, b"abc", "../tests/spicy/types/bytes/parse-length.spicy:20:10-20:15", Null);
    __cur = __cur.advance(3);

    if ( __trim )
        (*__data).trim(begin(__cur));

    # End parsing production: Ctor: b1  -> b"abc" (const bytes)
```
  • Loading branch information
rsmmr committed Sep 26, 2024
1 parent e64facf commit 94494a6
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 69 deletions.
2 changes: 1 addition & 1 deletion spicy/lib/spicy_rt.hlt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ declare public void backtrack() &cxxname="spicy::rt::detail::backtrack" &have_pr
declare public void initializeParsedUnit(inout ParsedUnit punit, any unit, TypeInfo ti) &cxxname="spicy::rt::ParsedUnit::initialize" &have_prototype;

declare public bytes extractBytes(inout value_ref<stream> data, view<stream> cur, uint<64> n, bool eod_ok, string location, inout strong_ref<Filters> filters) &cxxname="spicy::rt::detail::extractBytes" &have_prototype;
declare public void expectBytesLiteral(inout value_ref<stream> data, view<stream> cur, bytes literal, string location, inout strong_ref<Filters> filters) &cxxname="spicy::rt::detail::expectBytesLiteral" &have_prototype;
declare public bytes expectBytesLiteral(inout value_ref<stream> data, view<stream> cur, bytes literal, string location, inout strong_ref<Filters> filters) &cxxname="spicy::rt::detail::expectBytesLiteral" &have_prototype;

}
8 changes: 5 additions & 3 deletions spicy/runtime/include/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,11 +553,13 @@ hilti::rt::Bytes extractBytes(hilti::rt::ValueReference<hilti::rt::Stream>& data
* @param literal raw bytes representation of the literal to extract
* @param location location associated with the situation
* @param filters filter state associated with current unit instance (which may be null)
* @returns `literal` (for convenience)
* @throws ParseError if the literal isn't found at the beginning of *cur*
*/
void expectBytesLiteral(hilti::rt::ValueReference<hilti::rt::Stream>& data, const hilti::rt::stream::View& cur,
const hilti::rt::Bytes& literal, std::string_view location,
const hilti::rt::StrongReference<spicy::rt::filter::detail::Filters>& filters);
hilti::rt::Bytes expectBytesLiteral(hilti::rt::ValueReference<hilti::rt::Stream>& data,
const hilti::rt::stream::View& cur, hilti::rt::Bytes literal,
std::string_view location,
const hilti::rt::StrongReference<spicy::rt::filter::detail::Filters>& filters);

} // namespace detail
} // namespace spicy::rt
8 changes: 5 additions & 3 deletions spicy/runtime/src/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ hilti::rt::Bytes detail::extractBytes(hilti::rt::ValueReference<hilti::rt::Strea
return cur.sub(cur.begin() + size).data();
}

void detail::expectBytesLiteral(hilti::rt::ValueReference<hilti::rt::Stream>& data, const hilti::rt::stream::View& cur,
const hilti::rt::Bytes& literal, std::string_view location,
const hilti::rt::StrongReference<spicy::rt::filter::detail::Filters>& filters) {
hilti::rt::Bytes detail::expectBytesLiteral(
hilti::rt::ValueReference<hilti::rt::Stream>& data, const hilti::rt::stream::View& cur, hilti::rt::Bytes literal,
std::string_view location, const hilti::rt::StrongReference<spicy::rt::filter::detail::Filters>& filters) {
detail::waitForInput(data, cur, literal.size(),
hilti::rt::fmt("expected %" PRIu64 R"( bytes for bytes literal "%s")", literal.size(),
literal),
Expand All @@ -212,4 +212,6 @@ void detail::expectBytesLiteral(hilti::rt::ValueReference<hilti::rt::Stream>& da
throw ParseError(hilti::rt::fmt(R"(expected bytes literal "%s" but input starts with "%s")", literal, content),
location);
}

return literal;
}
2 changes: 1 addition & 1 deletion spicy/runtime/src/tests/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ TEST_CASE("expectBytesLiteral") {
data->freeze();
auto view = data->view();

CHECK_NOTHROW(detail::expectBytesLiteral(data, data->view(), "123"_b, "<location>", {}));
CHECK_EQ(detail::expectBytesLiteral(data, data->view(), "123"_b, "<location>", {}), "123"_b);
CHECK_THROWS_WITH_AS(detail::expectBytesLiteral(data, data->view(), "abc"_b, "<location>", {}),
"expected bytes literal \"abc\" but input starts with \"123\" (<location>)",
const spicy::rt::ParseError&);
Expand Down
29 changes: 18 additions & 11 deletions spicy/toolchain/src/compiler/codegen/parsers/literals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,32 +89,39 @@ struct Visitor : public visitor::PreOrder {
pb()->parseError("unexpected token to consume", n->meta());
popBuilder();

pushBuilder(
builder()->addIf(builder()->unequal(builder()->expression(n),
builder()->memberCall(state().cur, "sub",
{builder()->begin(state().cur),
state().lahead_end}))));
auto literal = builder()->addTmp("literal", builder()->expression(n));

pushBuilder(builder()->addIf(
builder()->unequal(literal, builder()->memberCall(state().cur, "sub",
{builder()->begin(state().cur),
state().lahead_end}))));
pb()->parseError("unexpected data when consuming token", n->meta());
popBuilder();

builder()->addAssign(lp->destination(n->type()->type()), literal);

pb()->consumeLookAhead();
popBuilder();

pushBuilder(no_lah);
}

builder()->addCall("spicy_rt::expectBytesLiteral",
{state().data, state().cur, builder()->expression(n),
builder()->expression(n->meta()), pb()->currentFilters(state())});
auto expect_bytes_literal =
builder()->call("spicy_rt::expectBytesLiteral",
{state().data, state().cur, builder()->expression(n),
builder()->expression(n->meta()), pb()->currentFilters(state())});


if ( state().literal_mode != LiteralMode::Skip )
builder()->addAssign(lp->destination(n->type()->type()), expect_bytes_literal);
else
builder()->addExpression(expect_bytes_literal);

pb()->advanceInput(len);

if ( check_for_look_ahead )
popBuilder();

if ( state().literal_mode != LiteralMode::Skip )
builder()->addAssign(lp->destination(n->type()->type()), builder()->expression(n));

result = builder()->expression(n);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
[debug/resolver] [spicy_rt.hlt:92:33-92:71] Attribute "&cxxname="spicy::rt::detail::backtrack"" -> Attribute "&cxxname="::spicy::rt::detail::backtrack""
[debug/resolver] [spicy_rt.hlt:94:89-94:132] Attribute "&cxxname="spicy::rt::ParsedUnit::initialize"" -> Attribute "&cxxname="::spicy::rt::ParsedUnit::initialize""
[debug/resolver] [spicy_rt.hlt:96:160-96:201] Attribute "&cxxname="spicy::rt::detail::extractBytes"" -> Attribute "&cxxname="::spicy::rt::detail::extractBytes""
[debug/resolver] [spicy_rt.hlt:97:155-97:202] Attribute "&cxxname="spicy::rt::detail::expectBytesLiteral"" -> Attribute "&cxxname="::spicy::rt::detail::expectBytesLiteral""
[debug/resolver] [spicy_rt.hlt:97:156-97:203] Attribute "&cxxname="spicy::rt::detail::expectBytesLiteral"" -> Attribute "&cxxname="::spicy::rt::detail::expectBytesLiteral""
[debug/resolver] [spicy.spicy:14:3-14:37] Attribute "&cxxname="hilti::rt::AddressFamily"" -> Attribute "&cxxname="::hilti::rt::AddressFamily""
[debug/resolver] [spicy.spicy:23:3-23:41] Attribute "&cxxname="hilti::rt::integer::BitOrder"" -> Attribute "&cxxname="::hilti::rt::integer::BitOrder""
[debug/resolver] [spicy.spicy:31:3-31:33] Attribute "&cxxname="hilti::rt::ByteOrder"" -> Attribute "&cxxname="::hilti::rt::ByteOrder""
Expand Down
48 changes: 24 additions & 24 deletions tests/Baseline/spicy.types.unit.hooks-across-imports/.stderr
Original file line number Diff line number Diff line change
@@ -1,55 +1,55 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
[debug/ast-stats] garbage collected 1098 nodes in 12 rounds, 8159 left retained
[debug/ast-stats] garbage collected 479 nodes in 11 rounds, 9404 left retained
[debug/ast-stats] garbage collected 170 nodes in 6 rounds, 9807 left retained
[debug/ast-stats] garbage collected 78 nodes in 3 rounds, 9807 left retained
[debug/ast-stats] garbage collected 78 nodes in 3 rounds, 9807 left retained
[debug/ast-stats] garbage collected 1098 nodes in 12 rounds, 8163 left retained
[debug/ast-stats] garbage collected 479 nodes in 11 rounds, 9412 left retained
[debug/ast-stats] garbage collected 170 nodes in 6 rounds, 9815 left retained
[debug/ast-stats] garbage collected 78 nodes in 3 rounds, 9815 left retained
[debug/ast-stats] garbage collected 78 nodes in 3 rounds, 9815 left retained
[debug/ast-stats] # [Spicy] AST statistics:
[debug/ast-stats] - # AST rounds 5
[debug/ast-stats] - max tree depth: 16
[debug/ast-stats] - # context declarations: 67
[debug/ast-stats] - # context types: 47
[debug/ast-stats] - # context modules: 5
[debug/ast-stats] - # nodes reachable in AST: 3201
[debug/ast-stats] - # nodes live: 9807
[debug/ast-stats] - # nodes retained: 9807
[debug/ast-stats] - # nodes reachable in AST: 3205
[debug/ast-stats] - # nodes live: 9815
[debug/ast-stats] - # nodes retained: 9815
[debug/ast-stats] - # nodes live > 1%:
[debug/ast-stats] - Attribute: 171
[debug/ast-stats] - AttributeSet: 341
[debug/ast-stats] - QualifiedType: 3318
[debug/ast-stats] - QualifiedType: 3322
[debug/ast-stats] - ctor::String: 120
[debug/ast-stats] - declaration::Parameter: 138
[debug/ast-stats] - expression::Ctor: 209
[debug/ast-stats] - type::Bool: 157
[debug/ast-stats] - type::Bytes: 151
[debug/ast-stats] - type::Bytes: 153
[debug/ast-stats] - type::Function: 134
[debug/ast-stats] - type::Member: 175
[debug/ast-stats] - type::OperandList: 670
[debug/ast-stats] - type::String: 215
[debug/ast-stats] - type::Unknown: 157
[debug/ast-stats] - type::UnsignedInteger: 533
[debug/ast-stats] - type::Void: 116
[debug/ast-stats] - type::bytes::Iterator: 179
[debug/ast-stats] - type::UnsignedInteger: 535
[debug/ast-stats] - type::Void: 114
[debug/ast-stats] - type::bytes::Iterator: 181
[debug/ast-stats] - type::operand_list::Operand: 1257
[debug/ast-stats] - type::stream::Iterator: 141
[debug/ast-stats] garbage collected 8966 nodes in 14 rounds, 21095 left retained
[debug/ast-stats] garbage collected 2310 nodes in 16 rounds, 24911 left retained
[debug/ast-stats] garbage collected 2346 nodes in 8 rounds, 26329 left retained
[debug/ast-stats] garbage collected 4594 nodes in 11 rounds, 27547 left retained
[debug/ast-stats] garbage collected 412 nodes in 3 rounds, 27547 left retained
[debug/ast-stats] garbage collected 8966 nodes in 14 rounds, 21103 left retained
[debug/ast-stats] garbage collected 2310 nodes in 16 rounds, 24919 left retained
[debug/ast-stats] garbage collected 2346 nodes in 8 rounds, 26337 left retained
[debug/ast-stats] garbage collected 4594 nodes in 11 rounds, 27555 left retained
[debug/ast-stats] garbage collected 412 nodes in 3 rounds, 27555 left retained
[debug/ast-stats] # [HILTI] AST statistics:
[debug/ast-stats] - # AST rounds 5
[debug/ast-stats] - max tree depth: 27
[debug/ast-stats] - # context declarations: 254
[debug/ast-stats] - # context types: 55
[debug/ast-stats] - # context modules: 8
[debug/ast-stats] - # nodes reachable in AST: 18587
[debug/ast-stats] - # nodes live: 27547
[debug/ast-stats] - # nodes retained: 27547
[debug/ast-stats] - # nodes reachable in AST: 18591
[debug/ast-stats] - # nodes live: 27555
[debug/ast-stats] - # nodes retained: 27555
[debug/ast-stats] - # nodes live > 1%:
[debug/ast-stats] - Attribute: 301
[debug/ast-stats] - AttributeSet: 765
[debug/ast-stats] - QualifiedType: 9116
[debug/ast-stats] - QualifiedType: 9120
[debug/ast-stats] - declaration::Parameter: 399
[debug/ast-stats] - expression::Ctor: 770
[debug/ast-stats] - expression::Member: 314
Expand All @@ -61,10 +61,10 @@
[debug/ast-stats] - type::Optional: 465
[debug/ast-stats] - type::String: 441
[debug/ast-stats] - type::Tuple: 324
[debug/ast-stats] - type::UnsignedInteger: 1695
[debug/ast-stats] - type::UnsignedInteger: 1697
[debug/ast-stats] - type::operand_list::Operand: 1557
[debug/ast-stats] - type::stream::Iterator: 1016
[debug/ast-stats] - type::stream::View: 550
[debug/ast-stats] - type::tuple::Element: 673
[debug/ast-stats] garbage collected 32191 nodes in 18 rounds, 0 left retained
[debug/ast-stats] garbage collected 32199 nodes in 18 rounds, 0 left retained
[debug/ast-stats] garbage collected 0 nodes in 1 round, 0 left retained
48 changes: 24 additions & 24 deletions tests/Baseline/spicy.types.unit.sub-unit/.stderr
Original file line number Diff line number Diff line change
@@ -1,54 +1,54 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
[debug/ast-stats] garbage collected 1086 nodes in 12 rounds, 7903 left retained
[debug/ast-stats] garbage collected 282 nodes in 11 rounds, 9057 left retained
[debug/ast-stats] garbage collected 70 nodes in 2 rounds, 9413 left retained
[debug/ast-stats] garbage collected 70 nodes in 2 rounds, 9413 left retained
[debug/ast-stats] garbage collected 1086 nodes in 12 rounds, 7907 left retained
[debug/ast-stats] garbage collected 282 nodes in 11 rounds, 9065 left retained
[debug/ast-stats] garbage collected 70 nodes in 2 rounds, 9421 left retained
[debug/ast-stats] garbage collected 70 nodes in 2 rounds, 9421 left retained
[debug/ast-stats] # [Spicy] AST statistics:
[debug/ast-stats] - # AST rounds 4
[debug/ast-stats] - max tree depth: 16
[debug/ast-stats] - # context declarations: 60
[debug/ast-stats] - # context types: 43
[debug/ast-stats] - # context modules: 4
[debug/ast-stats] - # nodes reachable in AST: 2805
[debug/ast-stats] - # nodes live: 9413
[debug/ast-stats] - # nodes retained: 9413
[debug/ast-stats] - # nodes reachable in AST: 2809
[debug/ast-stats] - # nodes live: 9421
[debug/ast-stats] - # nodes retained: 9421
[debug/ast-stats] - # nodes live > 1%:
[debug/ast-stats] - Attribute: 166
[debug/ast-stats] - AttributeSet: 317
[debug/ast-stats] - QualifiedType: 3188
[debug/ast-stats] - QualifiedType: 3192
[debug/ast-stats] - ctor::String: 112
[debug/ast-stats] - declaration::Parameter: 138
[debug/ast-stats] - expression::Ctor: 196
[debug/ast-stats] - type::Bool: 157
[debug/ast-stats] - type::Bytes: 120
[debug/ast-stats] - type::Bytes: 122
[debug/ast-stats] - type::Function: 127
[debug/ast-stats] - type::Member: 167
[debug/ast-stats] - type::OperandList: 670
[debug/ast-stats] - type::String: 207
[debug/ast-stats] - type::Unknown: 157
[debug/ast-stats] - type::UnsignedInteger: 508
[debug/ast-stats] - type::Void: 109
[debug/ast-stats] - type::bytes::Iterator: 148
[debug/ast-stats] - type::UnsignedInteger: 510
[debug/ast-stats] - type::Void: 107
[debug/ast-stats] - type::bytes::Iterator: 150
[debug/ast-stats] - type::operand_list::Operand: 1257
[debug/ast-stats] - type::stream::Iterator: 141
[debug/ast-stats] garbage collected 5080 nodes in 12 rounds, 17788 left retained
[debug/ast-stats] garbage collected 2884 nodes in 16 rounds, 20614 left retained
[debug/ast-stats] garbage collected 1582 nodes in 8 rounds, 21511 left retained
[debug/ast-stats] garbage collected 3397 nodes in 11 rounds, 22304 left retained
[debug/ast-stats] garbage collected 286 nodes in 3 rounds, 22304 left retained
[debug/ast-stats] garbage collected 5080 nodes in 12 rounds, 17796 left retained
[debug/ast-stats] garbage collected 2884 nodes in 16 rounds, 20622 left retained
[debug/ast-stats] garbage collected 1582 nodes in 8 rounds, 21519 left retained
[debug/ast-stats] garbage collected 3397 nodes in 11 rounds, 22312 left retained
[debug/ast-stats] garbage collected 286 nodes in 3 rounds, 22312 left retained
[debug/ast-stats] # [HILTI] AST statistics:
[debug/ast-stats] - # AST rounds 5
[debug/ast-stats] - max tree depth: 27
[debug/ast-stats] - # context declarations: 189
[debug/ast-stats] - # context types: 49
[debug/ast-stats] - # context modules: 6
[debug/ast-stats] - # nodes reachable in AST: 14254
[debug/ast-stats] - # nodes live: 22304
[debug/ast-stats] - # nodes retained: 22304
[debug/ast-stats] - # nodes reachable in AST: 14258
[debug/ast-stats] - # nodes live: 22312
[debug/ast-stats] - # nodes retained: 22312
[debug/ast-stats] - # nodes live > 1%:
[debug/ast-stats] - Attribute: 251
[debug/ast-stats] - AttributeSet: 593
[debug/ast-stats] - QualifiedType: 7347
[debug/ast-stats] - QualifiedType: 7351
[debug/ast-stats] - ctor::String: 290
[debug/ast-stats] - declaration::Parameter: 307
[debug/ast-stats] - expression::Ctor: 695
Expand All @@ -60,11 +60,11 @@
[debug/ast-stats] - type::Optional: 339
[debug/ast-stats] - type::String: 536
[debug/ast-stats] - type::Tuple: 269
[debug/ast-stats] - type::UnsignedInteger: 1290
[debug/ast-stats] - type::Void: 253
[debug/ast-stats] - type::UnsignedInteger: 1292
[debug/ast-stats] - type::Void: 251
[debug/ast-stats] - type::operand_list::Operand: 1451
[debug/ast-stats] - type::stream::Iterator: 763
[debug/ast-stats] - type::stream::View: 417
[debug/ast-stats] - type::tuple::Element: 600
[debug/ast-stats] garbage collected 23630 nodes in 18 rounds, 0 left retained
[debug/ast-stats] garbage collected 23638 nodes in 18 rounds, 0 left retained
[debug/ast-stats] garbage collected 0 nodes in 1 round, 0 left retained
2 changes: 1 addition & 1 deletion tests/spicy/types/bytes/parse-length.spicy
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# @TEST-EXEC: spicyc -p %INPUT | grep -q 'b2 = spicy_rt::extractBytes'
#
# Ensure literal-specific optimization kicks in.
# @TEST-EXEC: spicyc -p %INPUT | grep -q '^ *spicy_rt::expectBytesLiteral'
# @TEST-EXEC: spicyc -p %INPUT | grep -q ' = spicy_rt::expectBytesLiteral'
#
# Ensure we don't get any look-ahead checks when parsing the literals, we don't need them here.
# @TEST-EXEC: spicyc -p %INPUT | grep -vq 'if.*lah'
Expand Down

0 comments on commit 94494a6

Please sign in to comment.