From 1c25f1b9a880e56f45ade7cdfc0a10ea09331ba8 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 31 Aug 2023 12:10:33 +0200 Subject: [PATCH] Support bitfield constants in Spicy for parsing. One can now define bitfield "constants" for parsing by providing integer expressions with fields: type Foo = unit { x: bitfield(8) { a: 0..3 = 2; b: 4..7; c: 7 = 1; }; This will first parse the bitfield as usual and then enforce that the two bit ranges that are coming with expressions (i.e., `a` and `c`) indeed containing the expected values. If they don't, that's a parse error. We also support using such bitfield constants for look-ahead parsing: type Foo = unit { x: uint8[]; y: bitfield(8) { a: 0..3 = 4; b: 4..7; }; }; This will parse uint8s until a value is discovered that has its bits set as defined by the bitfield constant. (We use the term "constant" loosely here: only the bits with values are actually enforced to be constant, all others are parsed as usual.) Closes #1467. --- doc/autogen/types/bitfield.rst | 2 +- doc/examples/_skip.spicy | 9 +++ doc/programming/language/types.rst | 12 ++++ doc/programming/parsing.rst | 31 ++++++-- .../include/ast/operators/bitfield.h | 5 +- spicy/toolchain/src/ast/types.cc | 3 +- .../src/compiler/codegen/parsers/literals.cc | 71 +++++++++++++++++++ .../src/compiler/codegen/parsers/types.cc | 29 ++++---- spicy/toolchain/src/compiler/parser/parser.yy | 15 ++-- .../src/compiler/visitors/resolver.cc | 10 +++ .../spicy.types.bitfield.ctor-fail/output | 6 ++ .../output | 2 + .../Baseline/spicy.types.bitfield.ctor/output | 3 + .../spicy.types.bitfield.width-fail/output | 4 +- .../output | 14 ++-- tests/spicy/types/bitfield/ctor-fail.spicy | 16 +++++ .../types/bitfield/ctor-look-ahead.spicy | 17 +++++ tests/spicy/types/bitfield/ctor.spicy | 17 +++++ .../types/unit/synchronize-literals.spicy | 17 +++-- 19 files changed, 240 insertions(+), 43 deletions(-) create mode 100644 doc/examples/_skip.spicy create mode 100644 tests/Baseline/spicy.types.bitfield.ctor-fail/output create mode 100644 tests/Baseline/spicy.types.bitfield.ctor-look-ahead/output create mode 100644 tests/Baseline/spicy.types.bitfield.ctor/output create mode 100644 tests/spicy/types/bitfield/ctor-fail.spicy create mode 100644 tests/spicy/types/bitfield/ctor-look-ahead.spicy create mode 100644 tests/spicy/types/bitfield/ctor.spicy diff --git a/doc/autogen/types/bitfield.rst b/doc/autogen/types/bitfield.rst index 88a1a47e9..5770343e9 100644 --- a/doc/autogen/types/bitfield.rst +++ b/doc/autogen/types/bitfield.rst @@ -2,7 +2,7 @@ .. spicy:operator:: bitfield::HasMember bool t:bitfield op:?. t: - Returns true if the bitfield's element has a value to provide. + Returns true if the bitfield's element has a value. .. spicy:operator:: bitfield::Member t:bitfield op:. t: diff --git a/doc/examples/_skip.spicy b/doc/examples/_skip.spicy new file mode 100644 index 000000000..bb64e1d9c --- /dev/null +++ b/doc/examples/_skip.spicy @@ -0,0 +1,9 @@ +# Automatically generated; edit in Sphinx source code, not here. +module Test; + +public type Foo = unit { + x: int8; + : skip bytes &size=5; + y: int8; + on %done { print self; } +}; \ No newline at end of file diff --git a/doc/programming/language/types.rst b/doc/programming/language/types.rst index 3cf40d9c6..418a4ac3e 100644 --- a/doc/programming/language/types.rst +++ b/doc/programming/language/types.rst @@ -40,6 +40,18 @@ parsed inside a unit. - Each ``RANGE`` has one of the forms ``LABEL: A`` or ``LABEL: A..B`` where ``A`` and ``B`` are bit numbers. +.. rubric:: Constants + +- ``bitfield(N) { RANGE_1 [= VALUE_1]; ...; RANGE_N [= VALUE_N] }`` + +A bitfield constant represents expected values for all or some of the +individual bitranges. They can be used only for parsing inside a unit +field, not as values to otherwise operate with. To define such a +constant with expected values, add ``= VALUE`` to the bitranges inside +the type definition as suitable (with ``VALUE`` representing the final +value after applying any ``&bit-order`` attribute, if present). See +:ref:`parse_bitfield` for more information. + .. include:: /autogen/types/bitfield.rst .. _type_bool: diff --git a/doc/programming/parsing.rst b/doc/programming/parsing.rst index e421cb277..6bf85c449 100644 --- a/doc/programming/parsing.rst +++ b/doc/programming/parsing.rst @@ -969,12 +969,12 @@ Example: Bitfield ^^^^^^^^ -Bitfields parse an integer value of a given size, and then make -selected smaller bit ranges within that value available individually -through dedicated identifiers. For example, the following unit parses -4 bytes as an ``uint32`` and then makes the value of bit 0 available -as ``f.x1``, bits 1 to 2 as ``f.x2``, and bits 3 to 4 as ``f.x3``, -respectively: +:ref:`Bitfields ` parse an integer value of a given +size, and then make selected smaller bit ranges within that value +available individually through dedicated identifiers. For example, the +following unit parses 4 bytes as an ``uint32`` and then makes the +value of bit 0 available as ``f.x1``, bits 1 to 2 as ``f.x2``, and +bits 3 to 4 as ``f.x3``, respectively: .. spicy-code:: parse-bitfield.spicy @@ -1037,6 +1037,25 @@ range to an enum, using ``$$`` to access the parsed value: :exec: printf '\x21' | spicy-driver %INPUT :show-with: foo.spicy +When parsing a bitfield, you can enforce expected values for some +or all of the bitranges through an assignment-style syntax: + +.. spicy-code:: + + type Foo = unit { + f: bitfield(8) { + x1: 0..3 = 2; + x2: 4..5; + x3: 6..7 = 3; + } + }; + +Now parsing will fail if values of ``x1`` and ``x3`` aren't ``2`` and +``3``, respectively. Internally, Spicy treats bitfields with such +expected values similar to constants of other types, meaning they +operate as valid look-ahead symbols as well (see +:ref:`parse_lookahead`). + .. _parse_bytes: Bytes diff --git a/hilti/toolchain/include/ast/operators/bitfield.h b/hilti/toolchain/include/ast/operators/bitfield.h index c87b630f8..46635e784 100644 --- a/hilti/toolchain/include/ast/operators/bitfield.h +++ b/hilti/toolchain/include/ast/operators/bitfield.h @@ -10,11 +10,10 @@ #include #include #include +#include #include #include -#include "ast/types/bool.h" - namespace hilti::operator_ { namespace bitfield::detail { @@ -94,7 +93,7 @@ BEGIN_OPERATOR_CUSTOM(bitfield, HasMember) detail::checkName(i.op0(), i.op1(), p.node); } - std::string doc() const { return "Returns true if the bitfield's element has a value to provide."; } + std::string doc() const { return "Returns true if the bitfield's element has a value."; } END_OPERATOR_CUSTOM } // namespace hilti::operator_ diff --git a/spicy/toolchain/src/ast/types.cc b/spicy/toolchain/src/ast/types.cc index c10de994e..141e915b7 100644 --- a/spicy/toolchain/src/ast/types.cc +++ b/spicy/toolchain/src/ast/types.cc @@ -2,11 +2,12 @@ #include "spicy/ast/types.h" +#include #include #include #include bool spicy::type::supportsLiterals(const hilti::Type& t) { return t.isA() || t.isA() || t.isA() || - t.isA(); + t.isA() || t.isA(); } diff --git a/spicy/toolchain/src/compiler/codegen/parsers/literals.cc b/spicy/toolchain/src/compiler/codegen/parsers/literals.cc index fa8374afd..db7e5678a 100644 --- a/spicy/toolchain/src/compiler/codegen/parsers/literals.cc +++ b/spicy/toolchain/src/compiler/codegen/parsers/literals.cc @@ -263,6 +263,77 @@ struct Visitor : public hilti::visitor::PreOrder, Visi result_t operator()(const hilti::ctor::SignedInteger& c) { return parseInteger(c.type(), builder::expression(c), c.meta()); } + + result_t operator()(const hilti::ctor::Bitfield& c) { + auto offset = [](Expression view) { return builder::memberCall(std::move(view), "offset", {}); }; + + switch ( state().literal_mode ) { + case LiteralMode::Default: + case LiteralMode::Skip: { + auto [have_lah, no_lah] = builder()->addIfElse(state().lahead); + + pushBuilder(have_lah); + + pushBuilder(builder()->addIf(builder::unequal(state().lahead, builder::integer(production.tokenID())))); + pb->parseError("unexpected token to consume", c.meta()); + popBuilder(); + + // Need to reparse the value to assign it to our destination. + auto value = pb->parseType(c.btype(), production.meta(), {}); + builder()->addAssign(destination(c.btype()), value); + + pb->consumeLookAhead(); + popBuilder(); + + pushBuilder(no_lah); + auto old_cur = builder()->addTmp("ocur", state().cur); + + value = pb->parseType(c.btype(), production.meta(), {}); + + // Check that the bit values match what we expect. + for ( const auto& b : c.bits() ) { + auto error = builder()->addIf(builder::unequal(builder::member(value, b.id()), b.expression())); + pushBuilder(error); + builder()->addAssign(state().cur, old_cur); + pb->parseError(fmt("unexpected value for bitfield element '%s'", b.id()), c.meta()); + popBuilder(); + } + + if ( state().literal_mode != LiteralMode::Skip ) + builder()->addAssign(destination(c.btype()), value); + + popBuilder(); + + return value; + } + + case LiteralMode::Search: // Handled in `parseLiteral`. + case LiteralMode::Try: { + auto old_cur = builder()->addTmp("ocur", state().cur); + auto bf = builder()->addTmp("bf", c.btype()); + pb->parseTypeTry(c.btype(), production.meta(), bf); + auto new_cur = builder()->addTmp("ncur", state().cur); + + auto match = builder()->addIf(builder::unequal(offset(old_cur), offset(new_cur))); + pushBuilder(match); + builder()->addAssign(state().cur, old_cur); // restore, because we must not move cur when in sync mode + + // Check that the bit values match what we expect. + for ( const auto& b : c.bits() ) { + auto error = builder()->addIf(builder::unequal(builder::member(bf, b.id()), b.expression())); + pushBuilder(error); + builder()->addAssign(new_cur, old_cur); // reset to old position + popBuilder(); + } + + popBuilder(); + + return builder::begin(new_cur); + } + } + + hilti::util::cannot_be_reached(); + } }; } // namespace diff --git a/spicy/toolchain/src/compiler/codegen/parsers/types.cc b/spicy/toolchain/src/compiler/codegen/parsers/types.cc index 23c1e99df..43809bffa 100644 --- a/spicy/toolchain/src/compiler/codegen/parsers/types.cc +++ b/spicy/toolchain/src/compiler/codegen/parsers/types.cc @@ -67,7 +67,7 @@ struct Visitor : public hilti::visitor::PreOrder { else { auto has_data = pb->waitForInputOrEod(builder::integer(len)); - auto result = builder()->addTmp("result", type::Result(t)); + auto result = dst ? *dst : builder()->addTmp("result", type::Result(t)); auto true_ = builder()->addIf(has_data); pushBuilder(true_); @@ -128,16 +128,19 @@ struct Visitor : public hilti::visitor::PreOrder { performUnpack(target, t, t.width() / 8, {state().cur, fieldByteOrder(), *bitorder}, t.meta(), is_try); if ( pb->options().debug ) { - // Print all the bit ranges individually so that we can include - // their IDs, which the standard tuple output wouldn't show. - builder()->addDebugMsg("spicy", fmt("%s = %%s", meta.field()->id()), - {builder::member(target, "__value__")}); - - builder()->addDebugIndent("spicy"); - for ( const auto& bits : t.bits() ) - builder()->addDebugMsg("spicy", fmt("%s = %%s", bits.id()), {builder::member(target, bits.id())}); - - builder()->addDebugDedent("spicy"); + auto have_value = builder()->addIf(builder::hasMember(target, "__value__")); + pushBuilder(have_value, [&]() { + // Print all the bit ranges individually so that we can include + // their IDs, which the standard tuple output wouldn't show. + builder()->addDebugMsg("spicy", fmt("%s = %%s", meta.field()->id()), + {builder::member(target, "__value__")}); + + builder()->addDebugIndent("spicy"); + for ( const auto& bits : t.bits() ) + builder()->addDebugMsg("spicy", fmt("%s = %%s", bits.id()), {builder::member(target, bits.id())}); + + builder()->addDebugDedent("spicy"); + }); } return target; @@ -303,7 +306,7 @@ struct Visitor : public hilti::visitor::PreOrder { Expression ParserBuilder::_parseType(const Type& t, const production::Meta& meta, const std::optional& dst, bool is_try) { - assert(! is_try || (t.isA() || t.isA())); + assert(! is_try || (t.isA() || t.isA() || t.isA())); if ( auto e = Visitor(this, meta, dst, is_try).dispatch(t) ) return std::move(*e); @@ -317,7 +320,7 @@ Expression ParserBuilder::parseType(const Type& t, const production::Meta& meta, Expression ParserBuilder::parseTypeTry(const Type& t, const production::Meta& meta, const std::optional& dst) { - assert(t.isA() || t.isA()); + assert(t.isA() || t.isA() || t.isA()); return _parseType(t, meta, dst, /*is_try =*/true); } diff --git a/spicy/toolchain/src/compiler/parser/parser.yy b/spicy/toolchain/src/compiler/parser/parser.yy index bf8d14ad5..658df127a 100644 --- a/spicy/toolchain/src/compiler/parser/parser.yy +++ b/spicy/toolchain/src/compiler/parser/parser.yy @@ -258,7 +258,7 @@ static std::vector _docs; %type expr tuple_elem tuple_expr member_expr ctor_expr expr_0 expr_1 expr_2 expr_3 expr_4 expr_5 expr_6 expr_7 expr_8 expr_9 expr_a expr_b expr_c expr_d expr_e expr_f expr_g %type > opt_tuple_elems1 opt_tuple_elems2 exprs opt_exprs opt_unit_field_args opt_unit_field_sinks %type > opt_else_block -%type > opt_init_expression opt_unit_field_condition unit_field_repeat opt_unit_field_repeat opt_unit_switch_expr +%type > opt_init_expression opt_unit_field_condition unit_field_repeat opt_unit_field_repeat opt_unit_switch_expr opt_bitfield_bits_value %type func_param %type opt_func_param_kind %type func_result opt_func_result @@ -702,10 +702,15 @@ bitfield_bits | bitfield_bits_spec { $$ = std::vector(); $$.push_back(std::move($1)); } bitfield_bits_spec - : local_id ':' CUINTEGER DOTDOT CUINTEGER opt_attributes ';' - { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $5, _field_width, std::move($6), __loc__); } - | local_id ':' CUINTEGER opt_attributes ';' - { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $3, _field_width, std::move($4), __loc__); } + : local_id ':' CUINTEGER DOTDOT CUINTEGER opt_bitfield_bits_value opt_attributes ';' + { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $5, _field_width, std::move($7), std::move($6), __loc__); } + | local_id ':' CUINTEGER opt_bitfield_bits_value opt_attributes ';' + { $$ = spicy::type::bitfield::Bits(std::move($1), $3, $3, _field_width, std::move($5), std::move($4), __loc__); } + +opt_bitfield_bits_value + : '=' expr { $$ = std::move($2); } + | /* empty */ { $$ = {}; } + ; /* --- Begin of Spicy units --- */ diff --git a/spicy/toolchain/src/compiler/visitors/resolver.cc b/spicy/toolchain/src/compiler/visitors/resolver.cc index 833e4a220..ba89dc29d 100644 --- a/spicy/toolchain/src/compiler/visitors/resolver.cc +++ b/spicy/toolchain/src/compiler/visitors/resolver.cc @@ -294,6 +294,16 @@ struct Visitor : public hilti::visitor::PreOrder { if ( ! type::isResolved(t) ) return; + if ( auto bf = t->tryAs() ) { + // If a bitfield type comes with values for at least one of its + // items, it's actually a bitfield ctor. Replace the type with the + // ctor then. + if ( auto ctor = bf->ctorValue() ) { + replaceField(&p, resolveField(u, *ctor)); + return; + } + } + replaceField(&p, resolveField(u, *t)); } diff --git a/tests/Baseline/spicy.types.bitfield.ctor-fail/output b/tests/Baseline/spicy.types.bitfield.ctor-fail/output new file mode 100644 index 000000000..15ab54776 --- /dev/null +++ b/tests/Baseline/spicy.types.bitfield.ctor-fail/output @@ -0,0 +1,6 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[error] <...>/ctor-fail.spicy:10:5: value is outside of bitfield element's range +[error] <...>/ctor-fail.spicy:11:5: value is outside of bitfield element's range +[error] <...>/ctor-fail.spicy:13:5: cannot coerce expression '-1' of type 'int<64>' to type 'uint<8>' +[error] <...>/ctor-fail.spicy:14:5: cannot coerce expression '"42"' of type 'string' to type 'uint<8>' +[error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.bitfield.ctor-look-ahead/output b/tests/Baseline/spicy.types.bitfield.ctor-look-ahead/output new file mode 100644 index 000000000..d604542fa --- /dev/null +++ b/tests/Baseline/spicy.types.bitfield.ctor-look-ahead/output @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +[$x=[1, 2, 3], $y=(4, 8), $z=5] diff --git a/tests/Baseline/spicy.types.bitfield.ctor/output b/tests/Baseline/spicy.types.bitfield.ctor/output new file mode 100644 index 000000000..078c6b08d --- /dev/null +++ b/tests/Baseline/spicy.types.bitfield.ctor/output @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +(2, 8, 1) +[error] terminating with uncaught exception of type spicy::rt::ParseError: unexpected value for bitfield element 'a' (<...>/ctor.spicy:10:6-14:4) diff --git a/tests/Baseline/spicy.types.bitfield.width-fail/output b/tests/Baseline/spicy.types.bitfield.width-fail/output index a2f94efa6..c1bab6426 100644 --- a/tests/Baseline/spicy.types.bitfield.width-fail/output +++ b/tests/Baseline/spicy.types.bitfield.width-fail/output @@ -1,4 +1,4 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[error] <...>/width-fail.spicy:9:8-12:6: upper limit is beyond the width of the bitfield -[error] <...>/width-fail.spicy:9:8-12:6: lower limit needs to be lower than upper limit +[error] <...>/width-fail.spicy:10:9: upper limit is beyond the width of the bitfield +[error] <...>/width-fail.spicy:11:9: lower limit needs to be lower than upper limit [error] spicyc: aborting after errors diff --git a/tests/Baseline/spicy.types.unit.synchronize-literals/output b/tests/Baseline/spicy.types.unit.synchronize-literals/output index 2511d41c5..375b4c365 100644 --- a/tests/Baseline/spicy.types.unit.synchronize-literals/output +++ b/tests/Baseline/spicy.types.unit.synchronize-literals/output @@ -1,7 +1,9 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -[$a=b"Axy", $b=6, $c=b"Cxy", $d=b"Dxy"] -[$a=(not set), $b=6, $c=b"Cxy", $d=b"Dxy"] -[$a=b"Axy", $b=(not set), $c=b"Cxy", $d=b"Dxy"] -[$a=b"Axy", $b=6, $c=(not set), $d=b"Dxy"] -[$a=b"Axy", $b=6, $c=(not set), $d=b"Dxy"] -[error] terminating with uncaught exception of type spicy::rt::ParseError: unexpected token to consume (<...>/synchronize-literals.spicy:23:8) +[$a=b"Axy", $b=6, $c=b"Cxy", $d=b"Dxy", $e=(1)] +[$a=(not set), $b=6, $c=b"Cxy", $d=b"Dxy", $e=(1)] +[$a=b"Axy", $b=(not set), $c=b"Cxy", $d=b"Dxy", $e=(1)] +[$a=b"Axy", $b=6, $c=(not set), $d=b"Dxy", $e=(1)] +[$a=b"Axy", $b=6, $c=(not set), $d=b"Dxy", $e=(1)] +[$a=b"Axy", $b=6, $c=b"Cxy", $d=(not set), $e=(1)] +[error] terminating with uncaught exception of type spicy::rt::ParseError: failed to synchronize: expecting 'Cxy' (<...>/synchronize-literals.spicy:24:8) +[error] terminating with uncaught exception of type spicy::rt::ParseError: failed to synchronize: failed to match regular expression (<...>/synchronize-literals.spicy:25:8) diff --git a/tests/spicy/types/bitfield/ctor-fail.spicy b/tests/spicy/types/bitfield/ctor-fail.spicy new file mode 100644 index 000000000..ac9618d7c --- /dev/null +++ b/tests/spicy/types/bitfield/ctor-fail.spicy @@ -0,0 +1,16 @@ +# @TEST-EXEC-FAIL: spicyc -j %INPUT >>output 2>&1 +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Check that we catch invalid bitfield constants. + +module Test; + +public type Foo = unit { + x: bitfield(8) { + a: 1..3 = 255; # error + b: 1..3 = 8; # error + c: 1..3 = 7; # ok + d: 4..7 = -1; + e: 4..7 = "42"; + }; +}; diff --git a/tests/spicy/types/bitfield/ctor-look-ahead.spicy b/tests/spicy/types/bitfield/ctor-look-ahead.spicy new file mode 100644 index 000000000..33e75502e --- /dev/null +++ b/tests/spicy/types/bitfield/ctor-look-ahead.spicy @@ -0,0 +1,17 @@ +# @TEST-EXEC: printf '\001\002\003\204\005' | spicy-driver %INPUT >>output +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Check look-ahead vector parsing with bitfield constant as terminator. + +module Test; + +public type Foo = unit { + x: uint8[]; + y: bitfield(8) { + a: 0..3 = 4; + b: 4..7; + }; + z: uint8; + + on %done { print self; } +}; diff --git a/tests/spicy/types/bitfield/ctor.spicy b/tests/spicy/types/bitfield/ctor.spicy new file mode 100644 index 000000000..41c100a88 --- /dev/null +++ b/tests/spicy/types/bitfield/ctor.spicy @@ -0,0 +1,17 @@ +# @TEST-EXEC: ${SCRIPTS}/printf '\x82' | spicy-driver %INPUT >>output 2>&1 +# @TEST-EXEC-FAIL: ${SCRIPTS}/printf '\200' | spicy-driver %INPUT >>output 2>&1 +# @TEST-EXEC: btest-diff output +# +# @TEST-DOC: Check bitfield constant parsing. + +module Test; + +public type Foo = unit { + x: bitfield(8) { + a: 0..3 = 2; + b: 4..7; + c: 7 = 1; + }; + + on %done { print self.x; } +}; diff --git a/tests/spicy/types/unit/synchronize-literals.spicy b/tests/spicy/types/unit/synchronize-literals.spicy index fb7d481a9..e4fcdd451 100644 --- a/tests/spicy/types/unit/synchronize-literals.spicy +++ b/tests/spicy/types/unit/synchronize-literals.spicy @@ -2,15 +2,17 @@ # @TEST-EXEC: spicyc -j -d %INPUT -o test.hlto # -# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxyDxy' | spicy-driver -i 1 -d test.hlto >>output 2>&1 -# @TEST-EXEC: ${SCRIPTS}/printf '\x00\x00\x00\x06CxyDxy' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxyDxy\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf '\x00\x00\x00\x06CxyDxy\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 # -# @TEST-EXEC: ${SCRIPTS}/printf 'AxyCxyDxy' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf 'AxyCxyDxy\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 # -# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06Dxy' | spicy-driver -i 1 -d test.hlto >>output 2>&1 -# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxDxy' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06Dxy\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxDxy\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxyXXX\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 -# @TEST-EXEC-FAIL: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxD' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC-FAIL: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxD\x80' | spicy-driver -i 1 -d test.hlto >>output 2>&1 +# @TEST-EXEC-FAIL: ${SCRIPTS}/printf 'Axy\x00\x00\x00\x06CxyXXX\x7f' | spicy-driver -i 1 -d test.hlto >>output 2>&1 # # @TEST-EXEC: btest-diff output @@ -21,6 +23,9 @@ public type X = unit { b: uint32(6) &synchronize; c: b"Cxy" &synchronize; d: /Dxy/ &synchronize; + e: bitfield(8) { + msb: 7 = 1; + } &synchronize; on %synced { confirm; } on %done { print self; }