rudy_dwarf/parser/
combinators.rs

1//! Generic parser combinators that work with any Parser implementations
2
3use anyhow::Context as _;
4
5use super::{Parser, Result};
6use crate::{Die, DwarfDb};
7
8/// Combinator that applies two parsers and combines their results
9pub struct And<P1, P2, T, U> {
10    pub(super) first: P1,
11    pub(super) second: P2,
12    pub(super) _marker: std::marker::PhantomData<(T, U)>,
13}
14
15impl<T, U, P1, P2> Parser<(T, U)> for And<P1, P2, T, U>
16where
17    P1: Parser<T>,
18    P2: Parser<U>,
19{
20    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<(T, U)> {
21        let first_result = self.first.parse(db, entry)?;
22        let second_result = self.second.parse(db, entry)?;
23        Ok((first_result, second_result))
24    }
25}
26
27/// Combinators that transforms parser output
28pub struct Map<P, F, T> {
29    pub(super) parser: P,
30    pub(super) f: F,
31    pub(super) _marker: std::marker::PhantomData<T>,
32}
33
34impl<T, U, P, F> Parser<U> for Map<P, F, T>
35where
36    P: Parser<T>,
37    F: Fn(T) -> U,
38{
39    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
40        let result = self.parser.parse(db, entry)?;
41        Ok((self.f)(result))
42    }
43}
44
45pub struct MapWithDb<P, F, T> {
46    pub(super) parser: P,
47    pub(super) f: F,
48    pub(super) _marker: std::marker::PhantomData<T>,
49}
50
51impl<T, U, P, F> Parser<U> for MapWithDb<P, F, T>
52where
53    P: Parser<T>,
54    F: Fn(&dyn DwarfDb, T) -> U,
55{
56    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
57        let result = self.parser.parse(db, entry)?;
58        Ok((self.f)(db, result))
59    }
60}
61
62pub struct MapWithDbAndEntry<P, F, T> {
63    pub(super) parser: P,
64    pub(super) f: F,
65    pub(super) _marker: std::marker::PhantomData<T>,
66}
67
68impl<T, U, P, F> Parser<U> for MapWithDbAndEntry<P, F, T>
69where
70    P: Parser<T>,
71    F: Fn(&dyn DwarfDb, Die, T) -> U,
72{
73    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
74        let result = self.parser.parse(db, entry)?;
75        Ok((self.f)(db, entry, result))
76    }
77}
78
79pub struct MapRes<P, F, T> {
80    pub(super) parser: P,
81    pub(super) f: F,
82    pub(super) _marker: std::marker::PhantomData<T>,
83}
84
85impl<T, U, P, F> Parser<U> for MapRes<P, F, T>
86where
87    P: Parser<T>,
88    F: Fn(T) -> Result<U>,
89{
90    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
91        let result = self.parser.parse(db, entry)?;
92        (self.f)(result)
93    }
94}
95
96/// Sequential combinator - applies parsers in sequence, each operating on the result of the previous
97pub struct Then<P1, P2, T> {
98    pub(super) first: P1,
99    pub(super) second: P2,
100    pub(super) _marker: std::marker::PhantomData<T>,
101}
102
103impl<U, P1, P2> Parser<U> for Then<P1, P2, Die>
104where
105    P1: Parser<Die>,
106    P2: Parser<U>,
107{
108    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
109        let intermediate = self.first.parse(db, entry)?;
110        self.second.parse(db, intermediate)
111    }
112}
113
114impl<U, P1, P2> Parser<Option<U>> for Then<P1, P2, Option<Die>>
115where
116    P1: Parser<Option<Die>>,
117    P2: Parser<U>,
118{
119    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<Option<U>> {
120        self.first
121            .parse(db, entry)?
122            .map(|intermediate| self.second.parse(db, intermediate))
123            .transpose()
124    }
125}
126
127impl<U, P1, P2> Parser<U> for Then<P1, P2, Result<Die>>
128where
129    P1: Parser<Result<Die>>,
130    P2: Parser<U>,
131{
132    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<U> {
133        self.first
134            .parse(db, entry)?
135            .and_then(|intermediate| self.second.parse(db, intermediate))
136    }
137}
138
139/// Combinator that filters the output of a parser, returning `None` if the parser fails
140pub struct Filter<P> {
141    pub(super) parser: P,
142}
143
144impl<T, P> Parser<Option<T>> for Filter<P>
145where
146    P: Parser<T>,
147{
148    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<Option<T>> {
149        Ok(self.parser.parse(db, entry).ok())
150    }
151}
152
153/// Combinator that adds context to errors
154pub struct Context<P> {
155    pub(super) parser: P,
156    pub(super) context: String,
157}
158
159impl<T, P> Parser<T> for Context<P>
160where
161    P: Parser<T>,
162{
163    fn parse(&self, db: &dyn DwarfDb, entry: Die) -> Result<T> {
164        self.parser
165            .parse(db, entry)
166            .with_context(|| entry.format_with_location(db, &self.context))
167    }
168}
169
170/// Combinator that applies multiple parsers and collects their results into a tuple
171pub fn all<T>(parsers: T) -> All<T> {
172    All { parsers }
173}
174
175pub struct All<T> {
176    pub(super) parsers: T,
177}
178
179/// Macro to dynamically generate All implementations
180///
181/// NOTE: it would be trivial to implement this for a bare tuple, but
182/// we prefer to use an explicit struct/combinator for this, since there are
183/// other methods like `parse_children` that explicitly expect a tuple of parsers,
184/// and we want to avoid mistakes like `for_each_child((parser1, parser2))` which would
185/// apply both parsers to the same child entry, rather than applying each parser to its own child.
186macro_rules! impl_parse_all_for_tuples {
187    (
188        $($P:ident, $T:ident, $idx:tt),*
189    ) => {
190        impl<$($T, $P,)*> Parser< ($($T,)*)> for All<($($P,)*)>
191        where
192            $($P: Parser< $T>),*
193        {
194            fn parse(&self, _db: &dyn DwarfDb, _entry: Die) -> anyhow::Result<($($T,)*)> {
195
196                Ok((
197                    $(
198                        self.parsers.$idx.parse(_db, _entry)?,
199                    )*
200                ))
201            }
202        }
203    };
204}
205
206// Generate implementations for different tuple sizes (0 to 8)
207impl_parse_all_for_tuples!();
208impl_parse_all_for_tuples!(P0, T0, 0);
209impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1);
210impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2);
211impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3);
212impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4);
213impl_parse_all_for_tuples!(P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5);
214impl_parse_all_for_tuples!(
215    P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5, P6, T6, 6
216);
217impl_parse_all_for_tuples!(
218    P0, T0, 0, P1, T1, 1, P2, T2, 2, P3, T3, 3, P4, T4, 4, P5, T5, 5, P6, T6, 6, P7, T7, 7
219);