Parcourir la source

`then` combinator to apply two parsers in order

Isaac Woods il y a 6 ans
Parent
commit
b4d5118904
2 fichiers modifiés avec 32 ajouts et 13 suppressions
  1. 1 1
      aml_parser/src/opcode.rs
  2. 31 12
      aml_parser/src/parser.rs

+ 1 - 1
aml_parser/src/opcode.rs

@@ -34,7 +34,7 @@ pub(crate) fn opcode<'a>(opcode: u8) -> impl Parser<'a, ()> {
 }
 
 pub(crate) fn ext_opcode<'a>(ext_opcode: u8) -> impl Parser<'a, ()> {
-    pair(opcode(EXT_OPCODE_PREFIX), opcode(ext_opcode)).map(|_| ())
+    opcode(EXT_OPCODE_PREFIX).then(opcode(ext_opcode)).map(|_| ())
 }
 
 #[cfg(test)]

+ 31 - 12
aml_parser/src/parser.rs

@@ -23,6 +23,13 @@ pub trait Parser<'a, R>: Sized {
     {
         Or { p1: self, p2: other, _phantom: PhantomData }
     }
+
+    fn then<NextParser, NextR>(self, next: NextParser) -> Then<'a, Self, NextParser, R, NextR>
+    where
+        NextParser: Parser<'a, NextR>,
+    {
+        Then { p1: self, p2: next, _phantom: PhantomData }
+    }
 }
 
 impl<'a, F, R> Parser<'a, R> for F
@@ -63,18 +70,6 @@ where
     }
 }
 
-pub fn pair<'a, P1, P2, R1, R2>(a: P1, b: P2) -> impl Parser<'a, (R1, R2)>
-where
-    P1: Parser<'a, R1>,
-    P2: Parser<'a, R2>,
-{
-    move |input| {
-        a.parse(input).and_then(|(next_input, result_a)| {
-            b.parse(next_input).map(|(final_input, result_b)| (final_input, (result_a, result_b)))
-        })
-    }
-}
-
 // TODO: can we make this formattable with stuff from the parse result?
 pub fn comment<'a, P, R>(parser: P, comment: &'static str) -> impl Parser<'a, R>
 where
@@ -131,6 +126,30 @@ where
     }
 }
 
+pub struct Then<'a, P1, P2, R1, R2>
+where
+    P1: Parser<'a, R1>,
+    P2: Parser<'a, R2>,
+{
+    p1: P1,
+    p2: P2,
+    _phantom: PhantomData<&'a (R1, R2)>,
+}
+
+impl<'a, P1, P2, R1, R2> Parser<'a, (R1, R2)> for Then<'a, P1, P2, R1, R2>
+where
+    P1: Parser<'a, R1>,
+    P2: Parser<'a, R2>,
+{
+    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, (R1, R2)> {
+        self.p1.parse(input).and_then(|(next_input, result_a)| {
+            self.p2
+                .parse(next_input)
+                .map(|(final_input, result_b)| (final_input, (result_a, result_b)))
+        })
+    }
+}
+
 /// Takes a number of parsers, and tries to apply each one to the input in order. Returns the
 /// result of the first one that succeeds, or fails if all of them fail.
 pub macro choice {