Error contexts and the permutation
combinator
#616
Replies: 4 comments 2 replies
-
You mentioned the solution ( To deal with a bad key inside a permutation, you can do |
Beta Was this translation helpful? Give feedback.
-
Hi, My apologies for the lack of details. The best I can do at the moment is the pub fn settings<'i, E>(input: &mut Input<'i>) -> PResult<(), E>
where
E: ParserError<Input<'i>> + AddContext<Input<'i>, StrContext>,
{
delimited(
delimited(ws, literal("settings"), preceded(ws, equal)),
delimited(
delimited(ws, open_brace, ws),
alt((
permutation((
preceded(delimited(ws, skip_comments, ws), primary),
preceded(delimited(ws, skip_comments, ws), backups),
preceded(delimited(ws, skip_comments, ws), max_attempts),
preceded(delimited(ws, skip_comments, ws), mount_point),
preceded(delimited(ws, skip_comments, ws), check_bootkey_integrity),
preceded(delimited(ws, skip_comments, ws), decryption_archive),
))
.void(),
fail.context(StrContext::Label("attribute"))
.context(StrContext::Expected("primary".into()))
.context(StrContext::Expected("backups".into()))
.context(StrContext::Expected("maxAttempts".into()))
.context(StrContext::Expected("mountPoint".into()))
.context(StrContext::Expected("checkBootkeyIntegrity".into()))
.context(StrContext::Expected("decryptionArchive".into())),
)),
preceded(ws, close_brace),
),
terminated(semi_column, ws),
)
.context(StrContext::Label("attribute-set `settings`"))
.parse_next(input)
} Input: settings = {
# Primary boot-key.
primary = {
id = "usb-JetFlash_Transcend_16GB_89J2FGNY7QARQPTD-0:0-part1";
£label = "primary";
creationDate = "2024-10-29T10:20:00+00:00";
lastUpdated = "2024-10-29T15:20:00+00:00";
};
# List of backup boot-keys.
backups = [];
# Maximum number of decryption attempts before program termination
# range [1-65535].
maxAttempts = 3;
# Mount location of the primary boot-key.
mountPoint = "/boot";
# Refuse to boot from a bootkey other than the primary or a member
# of the backup list if set to 'true'.
checkBootkeyIntegrity = false;
# Location of the archive containing a LUKS keyfile and header file
# necessary for device decryption.
decryptionArchive = "/etc/nixos/initrd/secrets/secboot";
}; Every child parser in the preceded(delimited(ws, skip_comments, ws), primary),
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^^^^^^^
// Always succeeds in all children The error occurs here Running the program with the function above gives the following error: error: invalid attribute
expected `primary`, `backups`, `maxAttempts`, `mountPoint`, `checkBootkeyIntegrity`, `decryptionArchive`
|
2 | # Primary boot-key.
| ^
| As far as I can tell, the error message tells me where the parser was before Each child parser does not fail equally, some bail earlier than others. settings = {
# Primary boot-key.
primary = {
# ^
# │
# └ all child parsers, except the `primary` parser, fail here (as expected).
id = "usb-JetFlash_Transcend_16GB_89J2FGNY7QARQPTD-0:0-part1";
£label = "primary";
# ^
# │
# └ the `primary` parser fails here
creationDate = "2024-10-29T10:20:00+00:00";
lastUpdated = "2024-10-29T15:20:00+00:00";
};
...snip... I tried introducing pub fn settings<'i, E>(input: &mut Input<'i>) -> PResult<(), E>
where
E: ParserError<Input<'i>> + AddContext<Input<'i>, StrContext>,
{
delimited(
delimited(ws, literal("settings"), preceded(ws, equal)),
delimited(
delimited(ws, open_brace, ws),
alt((
permutation((
preceded(delimited(ws, skip_comments, ws), cut_err(primary)),
preceded(delimited(ws, skip_comments, ws), cut_err(backups)),
preceded(delimited(ws, skip_comments, ws), cut_err(max_attempts)),
preceded(delimited(ws, skip_comments, ws), cut_err(mount_point)),
preceded(
delimited(ws, skip_comments, ws),
cut_err(check_bootkey_integrity),
),
preceded(
delimited(ws, skip_comments, ws),
cut_err(decryption_archive),
),
))
.void(),
fail.context(StrContext::Label("attribute"))
.context(StrContext::Expected("primary".into()))
.context(StrContext::Expected("backups".into()))
.context(StrContext::Expected("maxAttempts".into()))
.context(StrContext::Expected("mountPoint".into()))
.context(StrContext::Expected("checkBootkeyIntegrity".into()))
.context(StrContext::Expected("decryptionArchive".into())),
)),
preceded(ws, close_brace),
),
terminated(semi_column, ws),
)
.context(StrContext::Label("attribute-set `settings`"))
.parse_next(input)
} With the same input, I get the right error line...but the wrong context. error: invalid attribute `creationDate`
|
5 | £label = "primary";
| ^
| Close but, unfortunately, not what I was looking for 😢 error: invalid attribute `label`
|
5 | £label = "primary";
| ^
| Adding settings = {
# Maximum number of decryption attempts before program termination
# range [1-65535].
maxAttempts = 3;
# List of backup boot-keys.
backups = [];
# Primary boot-key.
primary = {
id = "usb-JetFlash_Transcend_16GB_89J2FGNY7QARQPTD-0:0-part1";
£label = "primary";
creationDate = "2024-10-29T10:20:00+00:00";
lastUpdated = "2024-10-29T15:20:00+00:00";
};
# Mount location of the primary boot-key.
mountPoint = "/boot";
# Refuse to boot from a bootkey other than the primary or a member
# of the backup list if set to 'true'.
checkBootkeyIntegrity = false;
# Location of the archive containing a LUKS keyfile and header file
# necessary for device decryption.
decryptionArchive = "/etc/nixos/initrd/secrets/secboot";
}; I get: error: invalid attribute `primary`
|
4 | maxAttempts = 3;
| ^
| ...when I would have expected: error: invalid attribute `label`
|
12 | £label = "primary";
| ^
| Which is due, I suspect, to Using cut_err(preceded(delimited(ws, skip_comments, ws), primary)), I went through the documentation, which is by the way one of the best I "I went through the parsers in the Hope this longer exposé helps 😄 Thanks! |
Beta Was this translation helpful? Give feedback.
-
Hi,
Are you saying that you would like to see the whole program? Did the file I attached to my first message fail to decompress? To give as much information as possible, I attached a minimal project containing the whole code to my initial message. I am attaching it again here example.tar.gz. |
Beta Was this translation helpful? Give feedback.
-
No worries,...it happens! 😉 I did not want to clutter by posting the almost 400 lines of Will keep in mind the correct procedure from now on. |
Beta Was this translation helpful? Give feedback.
-
Hi,
First of all, thank you for
winnow
. I am fairly new to Rust, and working withwinnow
is an absolute delight.Context
I made a minimal program to illustrate my problem. See the files in
example.tar.gz:
Description
I am trying to parse the following structure in a
nix
file:settings
is an attribute-set with attributesprimary
,backups
,maxAttempts
,mountPoint
,checkBootkeyIntegrity
, anddecryptionArchive
.I am using a function to parse
settings
resembling the snippet below (takenfrom the
parsers.rs
file attached to this question).It is a streamlined version of the one I am developing. Attributes can come in
any order. Hence, an application of the
permutation
combinator.Each parser for
primary
,backups
, etc. reports a context when an error occurs.permutation
will succeed if all child parsers succeed. Currently, if any ofthe child parsers fails
permutation
will always report the context of the last childparser in the tuple (i.e.
decryption_archive
).For example, if I introduce an error in the input, here a
£
sign beforelabel
:The program will report:
Even though
decryptionArchive
is correct, the error says it is not whilereturning the wrong error location.
I would have expected the following error:
How can I get the
premutation
combinator to report the error context of theparser that was the farthest along, even it ultimately failed, or the error
context of the first of the remaining child parsers that failed when at least
one succeeded?
The tutorial provides an example for managing fall-through error reports with
the
alt
combinator using error cuts, but I could not get it to work as I wouldlike with the
permutation
combinator.Thanks for your help.
Beta Was this translation helpful? Give feedback.
All reactions