From d7dc372ffa23772b59353b4ac303ecd18ac1be28 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 23 Sep 2024 19:43:10 +0200 Subject: [PATCH] Fix parsing ambiguity with properties. In the past, we had special-cased properties in our Flex/Bison parser so that when parsing an expression, they wouldn't be recognized. However, that now led an error field hook of the form `x: bytes &size=42 %error` to be parsed as `&size=(42 % error)`. We now switch to white-listing all known properties, just as we already do for attributes. That way conflicts should be extremely rare. --- spicy/toolchain/src/compiler/parser/scanner.ll | 5 +++-- .../spicy.types.unit.error-hook-field/output | 17 ++++++++++------- .../spicy.types.unit.properties-fail/output | 3 +-- tests/spicy/types/unit/error-hook-field.spicy | 10 +++++++++- tests/spicy/types/unit/properties-fail.spicy | 1 - 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/spicy/toolchain/src/compiler/parser/scanner.ll b/spicy/toolchain/src/compiler/parser/scanner.ll index f7e7868a66..119da6ef5f 100644 --- a/spicy/toolchain/src/compiler/parser/scanner.ll +++ b/spicy/toolchain/src/compiler/parser/scanner.ll @@ -63,6 +63,8 @@ doc_text [ \t]*##[^\n]*\n? comment [ \t]*#[^#\n]*\n? attribute \&(bit-order|byte-order|chunked|convert|count|cxxname|default|eod|internal|ipv4|ipv6|hilti_type|length|max-size|no-emit|nosub|on-heap|optional|originator|parse-at|parse-from|requires|responder|size|static|synchronize|transient|try|type|until|until-including|while|have_prototype) +property %(byte-order|context|cxx-include|debug|description|done|error|filter|mime-type|orig|port|random-access|resp|s_default|skip|skip-implementation|skip-post|skip-pre|spicy-version|sync-advance-block-size|synchronize-after|synchronize-at) + blank [ \t] digit [0-9] digits {digit}+ @@ -73,7 +75,6 @@ P ([Pp][+-]?{digits}) decfloat {digits}{E}|{digit}*\.{digits}{E}?|{digits}\.{digit}+{E}? hexfloat 0[xX]({hexit}+{P}|{hexit}*\.{hexit}+{P}?|{hexit}+\.{hexit}+{P}?) id [a-zA-Z_]|[a-zA-Z_][a-zA-Z_0-9]*[a-zA-Z_0-9]|[$][$] -property %[a-zA-Z_][a-zA-Z_0-9-]* string \"(\\.|[^\\"])*\" preprocessor @[a-zA-Z_][a-zA-Z_0-9-]* @@ -231,7 +232,7 @@ Null return token::CNULL; skip return token::SKIP; {attribute} yylval->build(std::string(yytext)); return token::ATTRIBUTE; -{property} yylval->build(std::string(yytext)); return token::PROPERTY; +{property} yylval->build(std::string(yytext)); return token::PROPERTY; {digits}\/(tcp|udp) yylval->build(std::string(yytext)); return token::CPORT; {address4} yylval->build(std::string(yytext)); return token::CADDRESS; {address6} yylval->build(std::string(yytext, 1, strlen(yytext) - 2)); return token::CADDRESS; diff --git a/tests/Baseline/spicy.types.unit.error-hook-field/output b/tests/Baseline/spicy.types.unit.error-hook-field/output index ee0a2e5838..beea1f3313 100644 --- a/tests/Baseline/spicy.types.unit.error-hook-field/output +++ b/tests/Baseline/spicy.types.unit.error-hook-field/output @@ -3,21 +3,21 @@ field A standard unit %done, [$a=b"A", $b=b"B", $c=b"C"] --- -[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:21:8-21:11) +[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:25:8-25:11) field A standard field B %error, attached, [$a=b"A", $b=(not set), $c=(not set)] field B %error, external, [$a=b"A", $b=(not set), $c=(not set)] -field B %error, external, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:21:8-21:11), [$a=b"A", $b=(not set), $c=(not set)] +field B %error, external, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:25:8-25:11), [$a=b"A", $b=(not set), $c=(not set)] field B %error, inside unit, [$a=b"A", $b=(not set), $c=(not set)] -field B %error, inside unit, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:21:8-21:11), [$a=b"A", $b=(not set), $c=(not set)] +field B %error, inside unit, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:25:8-25:11), [$a=b"A", $b=(not set), $c=(not set)] unit %error, [$a=b"A", $b=(not set), $c=(not set)] -unit %error, external, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:21:8-21:11), [$a=b"A", $b=(not set), $c=(not set)] +unit %error, external, expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:25:8-25:11), [$a=b"A", $b=(not set), $c=(not set)] --- -[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "C" but input starts with "x" (<...>/error-hook-field.spicy:22:8-22:11) +[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "C" but input starts with "x" (<...>/error-hook-field.spicy:26:8-26:11) field A standard unit %error, [$a=b"A", $b=b"B", $c=(not set)] unit %error, external, [$a=b"A", $b=b"B", $c=(not set)] -unit %error, external, expected bytes literal "C" but input starts with "x" (<...>/error-hook-field.spicy:22:8-22:11), [$a=b"A", $b=b"B", $c=(not set)] +unit %error, external, expected bytes literal "C" but input starts with "x" (<...>/error-hook-field.spicy:26:8-26:11), [$a=b"A", $b=b"B", $c=(not set)] === --- unit %done, [$foo=[$a=b"A", $b=b"B"], $c=b"C"] @@ -25,5 +25,8 @@ unit %done, [$foo=[$a=b"A", $b=b"B"], $c=b"C"] field A %error unit %done, [$foo=[$a=(not set), $b=(not set)], $c=b"C"] --- -[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:66:8-66:11) +[error] terminating with uncaught exception of type spicy::rt::ParseError: expected bytes literal "B" but input starts with "x" (<...>/error-hook-field.spicy:69:8-69:11) unit %error, [$foo=[$a=b"A", $b=(not set)], $c=(not set)] +=== +[error] terminating with uncaught exception of type spicy::rt::ParseError: expected 5 bytes (4 bytes available) (<...>/error-hook-field.spicy:74:5-74:55) +field x %error diff --git a/tests/Baseline/spicy.types.unit.properties-fail/output b/tests/Baseline/spicy.types.unit.properties-fail/output index 6e75fe3423..eec9b8f9c9 100644 --- a/tests/Baseline/spicy.types.unit.properties-fail/output +++ b/tests/Baseline/spicy.types.unit.properties-fail/output @@ -1,6 +1,6 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. [warning] <...>/properties-fail.spicy:13:5-13:26: %random-access is no longer needed and deprecated -[error] <...>/properties-fail.spicy:19:3-19:13: &byte-order requires an expression +[error] <...>/properties-fail.spicy:18:3-18:13: &byte-order requires an expression [error] <...>/properties-fail.spicy:9:5-9:10: %port requires an argument [error] <...>/properties-fail.spicy:10:5-10:15: %port requires a port as its argument [error] <...>/properties-fail.spicy:11:5-11:17: %description requires an argument @@ -10,5 +10,4 @@ [error] <...>/properties-fail.spicy:15:5-15:15: %mime-type requires an argument [error] <...>/properties-fail.spicy:16:5-16:20: %mime-type requires a string argument [error] <...>/properties-fail.spicy:17:5-17:26: %mime-type argument must follow "main/sub" form -[error] <...>/properties-fail.spicy:18:5-18:13: unknown property '%unknown' [error] spicyc: aborting after errors diff --git a/tests/spicy/types/unit/error-hook-field.spicy b/tests/spicy/types/unit/error-hook-field.spicy index 0f9dbfab11..0d033e5c64 100644 --- a/tests/spicy/types/unit/error-hook-field.spicy +++ b/tests/spicy/types/unit/error-hook-field.spicy @@ -10,6 +10,10 @@ # @TEST-EXEC: echo C | spicy-driver -p Mini::Test2 test.hlto 2>&1 | sort >>output # @TEST-EXEC: echo AxC | (spicy-driver -p Mini::Test2 test.hlto 2>&1; true) | sort >>output # +# @TEST-EXEC: echo === >>output +# +# @TEST-EXEC: echo 123 | (spicy-driver -p Mini::Test3 test.hlto 2>&1; true) | sort >>output +# # @TEST-EXEC: btest-diff output module Mini; @@ -21,7 +25,6 @@ public type Test1 = unit { b: b"B" %error { print "field B %error, attached", self; } c: b"C"; - # TODO: These don't trigger yet on b %error { print "field B %error, inside unit", self; } @@ -65,3 +68,8 @@ type Foo = unit { a: b"A" %error { print "field A %error"; self.backtrack(); } b: b"B"; }; + +# Test that contains a field where Bison parsing is tricky. +public type Test3 = unit { + x: bytes &size=5 %error { print "field x %error"; } +}; diff --git a/tests/spicy/types/unit/properties-fail.spicy b/tests/spicy/types/unit/properties-fail.spicy index 8f3c2977aa..7b67fd8ee0 100644 --- a/tests/spicy/types/unit/properties-fail.spicy +++ b/tests/spicy/types/unit/properties-fail.spicy @@ -15,5 +15,4 @@ public type Foo = unit { %mime-type; %mime-type = 42; %mime-type = "kaputt"; - %unknown; } &byte-order;