Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding state to a nom parser

Tags:

state

rust

nom

I wrote a parser in nom that is completely stateless, now I need to wrap it in a few stateful layers.

I have a top-level parsing function named alt_fn that will provide me the next bit of parsed output as an enum variant, the details of which probably aren't important.

I have three things I need to do that involve state:

1) I need to conditionally perform a transformation on the output of alt_fn if there is a match in a non-mutable HashMap that is part of my State struct. This should basically be like a map! but as a method call on my struct. Something like this:

named!(alt_fn<AllTags> ,alt!(// snipped for brevity));

fn applyMath(self, i:AllTags)->AllTags { // snipped for brevity }

method!(apply_math<State, &[u8], AllTags>, mut self, call_m!(self.applyMath, call!(alt_fn)));

This currently gives me: error: unexpected end of macro invocation with alt_fn underlined.

2) I need to update the other fields of the state struct with the data I got from the input (such as computing checksums and updating timestamps, etc.), and then transform the output again with this new knowledge. This will probably look like the following:

fn updateState(mut self, i:AllTags) -> AllTags { // snipped for brevity }

method!(update_state<State, &[u8], AllTags>, mut self, call_m!(self.updateState, call_m!(self.applyMath)));

3) I need to call the method from part two repeatedly until all the input is used up:

method!(pub parse<State,&[u8],Vec<AllTags>>, mut self, many1!(update_state));

Unfortunately the nom docs are pretty limited, and I'm not great with macro syntax so I don't know what I'm doing wrong.

like image 366
Camden Narzt Avatar asked Sep 04 '26 01:09

Camden Narzt


1 Answers

When I need to do something complicated with nom, I normally write my own functions.

For example

named!(my_func<T>, <my_macros>);

is equivalent to

fn my_func(i: &[u8]) -> nom::IResult<T, &[u8]> {
    <my_macros>
}

with the proviso that you must pass i to the macro (see my comment).

Creating your own function means you can have any control flow you want in there, and it will play nice with nom as long as it takes a &[u8] and returns nom::IResult where the output &[u8] is the remaining unparsed raw input.

If you need some more info comment and I'll try to improve my answer!

like image 158
derekdreery Avatar answered Sep 05 '26 16:09

derekdreery



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!