Przeglądaj źródła

Allow access to the AmlContext throughout the parse

This should make it super easy to e.g. add stuff to the namespace, or
change the current scope. In the future, it will mean we can set and access
args and locals when we actually execute AML methods.

It does make the combinators more ugly, which bleeds into the imperatively
written parsers (e.g. raw_pkg_length). In the future, I hope to rewrite
these parsers to make use of more powerful combinators, but I haven't worked
out how yet.
Isaac Woods 5 lat temu
rodzic
commit
e2d469502a

+ 3 - 2
aml_parser/src/lib.rs

@@ -35,6 +35,7 @@ pub enum AmlError {
     InvalidFieldFlags,
     InvalidFieldFlags,
 }
 }
 
 
+#[derive(Debug)]
 pub struct AmlContext {
 pub struct AmlContext {
     namespace: BTreeMap<String, AmlValue>,
     namespace: BTreeMap<String, AmlValue>,
 }
 }
@@ -52,10 +53,10 @@ impl AmlContext {
         match term_object::term_list(
         match term_object::term_list(
             PkgLength::from_raw_length(stream, stream.len() as u32) as PkgLength
             PkgLength::from_raw_length(stream, stream.len() as u32) as PkgLength
         )
         )
-        .parse(stream)
+        .parse(stream, self)
         {
         {
             Ok(_) => Ok(()),
             Ok(_) => Ok(()),
-            Err((remaining, err)) => {
+            Err((remaining, _context, err)) => {
                 error!("Failed to parse AML stream. Err = {:?}", err);
                 error!("Failed to parse AML stream. Err = {:?}", err);
                 trace!("Remaining AML: {:02x?}", remaining);
                 trace!("Remaining AML: {:02x?}", remaining);
                 Err(err)
                 Err(err)

+ 60 - 31
aml_parser/src/name_object.rs

@@ -1,12 +1,16 @@
 use crate::{
 use crate::{
     opcode::{opcode, DUAL_NAME_PREFIX, MULTI_NAME_PREFIX, NULL_NAME, PREFIX_CHAR, ROOT_CHAR},
     opcode::{opcode, DUAL_NAME_PREFIX, MULTI_NAME_PREFIX, NULL_NAME, PREFIX_CHAR, ROOT_CHAR},
     parser::{choice, comment_scope, consume, n_of, take, Parser},
     parser::{choice, comment_scope, consume, n_of, take, Parser},
+    AmlContext,
     AmlError,
     AmlError,
 };
 };
 use alloc::string::String;
 use alloc::string::String;
 use core::str;
 use core::str;
 
 
-pub fn name_string<'a>() -> impl Parser<'a, String> {
+pub fn name_string<'a, 'c>() -> impl Parser<'a, 'c, String>
+where
+    'c: 'a,
+{
     /*
     /*
      * NameString := <RootChar('\') NamePath> | <PrefixPath NamePath>
      * NameString := <RootChar('\') NamePath> | <PrefixPath NamePath>
      * PrefixPath := Nothing | <'^' PrefixPath>
      * PrefixPath := Nothing | <'^' PrefixPath>
@@ -14,21 +18,27 @@ pub fn name_string<'a>() -> impl Parser<'a, String> {
     let root_name_string =
     let root_name_string =
         opcode(ROOT_CHAR).then(name_path()).map(|((), name_path)| String::from("\\") + &name_path);
         opcode(ROOT_CHAR).then(name_path()).map(|((), name_path)| String::from("\\") + &name_path);
 
 
-    comment_scope("NameString", move |input: &'a [u8]| {
-        let first_char = *input.first().ok_or((input, AmlError::UnexpectedEndOfStream))?;
+    comment_scope("NameString", move |input: &'a [u8], context: &'c mut AmlContext| {
+        let first_char = match input.first() {
+            Some(&c) => c,
+            None => return Err((input, context, AmlError::UnexpectedEndOfStream)),
+        };
 
 
         match first_char {
         match first_char {
-            ROOT_CHAR => root_name_string.parse(input),
+            ROOT_CHAR => root_name_string.parse(input, context),
             PREFIX_CHAR => {
             PREFIX_CHAR => {
                 // TODO: parse <PrefixPath NamePath> where there are actually PrefixChars
                 // TODO: parse <PrefixPath NamePath> where there are actually PrefixChars
                 unimplemented!();
                 unimplemented!();
             }
             }
-            _ => name_path().parse(input),
+            _ => name_path().parse(input, context),
         }
         }
     })
     })
 }
 }
 
 
-pub fn name_path<'a>() -> impl Parser<'a, String> {
+pub fn name_path<'a, 'c>() -> impl Parser<'a, 'c, String>
+where
+    'c: 'a,
+{
     /*
     /*
      * NamePath := NullName | DualNamePath | MultiNamePath | NameSeg
      * NamePath := NullName | DualNamePath | MultiNamePath | NameSeg
      */
      */
@@ -40,14 +50,20 @@ pub fn name_path<'a>() -> impl Parser<'a, String> {
     )
     )
 }
 }
 
 
-pub fn null_name<'a>() -> impl Parser<'a, String> {
+pub fn null_name<'a, 'c>() -> impl Parser<'a, 'c, String>
+where
+    'c: 'a,
+{
     /*
     /*
      * NullName := 0x00
      * NullName := 0x00
      */
      */
     opcode(NULL_NAME).map(|_| String::from(""))
     opcode(NULL_NAME).map(|_| String::from(""))
 }
 }
 
 
-pub fn dual_name_path<'a>() -> impl Parser<'a, String> {
+pub fn dual_name_path<'a, 'c>() -> impl Parser<'a, 'c, String>
+where
+    'c: 'a,
+{
     /*
     /*
      * DualNamePath := 0x2e NameSeg NameSeg
      * DualNamePath := 0x2e NameSeg NameSeg
      */
      */
@@ -57,19 +73,24 @@ pub fn dual_name_path<'a>() -> impl Parser<'a, String> {
         .map(|(((), first), second)| String::from(first.as_str()) + second.as_str())
         .map(|(((), first), second)| String::from(first.as_str()) + second.as_str())
 }
 }
 
 
-pub fn multi_name_path<'a>() -> impl Parser<'a, String> {
+pub fn multi_name_path<'a, 'c>() -> impl Parser<'a, 'c, String>
+where
+    'c: 'a,
+{
     /*
     /*
      * MultiNamePath := 0x2f ByteData{SegCount} NameSeg(SegCount)
      * MultiNamePath := 0x2f ByteData{SegCount} NameSeg(SegCount)
      */
      */
-    move |input| {
-        let (new_input, ((), seg_count)) = opcode(MULTI_NAME_PREFIX).then(take()).parse(input)?;
-        match n_of(name_seg(), usize::from(seg_count)).parse(new_input) {
-            Ok((new_input, name_segs)) => Ok((
+    move |input, context| {
+        let (new_input, context, ((), seg_count)) =
+            opcode(MULTI_NAME_PREFIX).then(take()).parse(input, context)?;
+        match n_of(name_seg(), usize::from(seg_count)).parse(new_input, context) {
+            Ok((new_input, context, name_segs)) => Ok((
                 new_input,
                 new_input,
+                context,
                 name_segs.iter().fold(String::new(), |name, name_seg| name + name_seg.as_str()),
                 name_segs.iter().fold(String::new(), |name, name_seg| name + name_seg.as_str()),
             )),
             )),
             // Correct returned input to the one we haven't touched
             // Correct returned input to the one we haven't touched
-            Err((_, err)) => Err((input, err)),
+            Err((_, context, err)) => Err((input, context, err)),
         }
         }
     }
     }
 }
 }
@@ -89,17 +110,20 @@ impl NameSeg {
     }
     }
 }
 }
 
 
-pub fn name_seg<'a>() -> impl Parser<'a, NameSeg> {
+pub fn name_seg<'a, 'c>() -> impl Parser<'a, 'c, NameSeg>
+where
+    'c: 'a,
+{
     /*
     /*
      * NameSeg := <LeadNameChar NameChar NameChar NameChar>
      * NameSeg := <LeadNameChar NameChar NameChar NameChar>
      */
      */
     // TODO: can we write this better?
     // TODO: can we write this better?
-    move |input| {
-        let (input, char_1) = consume(is_lead_name_char).parse(input)?;
-        let (input, char_2) = consume(is_name_char).parse(input)?;
-        let (input, char_3) = consume(is_name_char).parse(input)?;
-        let (input, char_4) = consume(is_name_char).parse(input)?;
-        Ok((input, NameSeg([char_1, char_2, char_3, char_4])))
+    move |input, context: &'c mut AmlContext| {
+        let (input, context, char_1) = consume(is_lead_name_char).parse(input, context)?;
+        let (input, context, char_2) = consume(is_name_char).parse(input, context)?;
+        let (input, context, char_3) = consume(is_name_char).parse(input, context)?;
+        let (input, context, char_4) = consume(is_name_char).parse(input, context)?;
+        Ok((input, context, NameSeg([char_1, char_2, char_3, char_4])))
     }
     }
 }
 }
 
 
@@ -118,33 +142,37 @@ fn is_name_char(byte: u8) -> bool {
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     use super::*;
     use super::*;
-    use crate::{parser::Parser, test_utils::*, AmlError};
+    use crate::{parser::Parser, test_utils::*, AmlContext, AmlError};
 
 
     #[test]
     #[test]
     fn test_name_seg() {
     fn test_name_seg() {
+        let mut context = AmlContext::new();
+
         check_ok!(
         check_ok!(
-            name_seg().parse(&[b'A', b'F', b'3', b'Z']),
+            name_seg().parse(&[b'A', b'F', b'3', b'Z'], &mut context),
             NameSeg([b'A', b'F', b'3', b'Z']),
             NameSeg([b'A', b'F', b'3', b'Z']),
             &[]
             &[]
         );
         );
         check_ok!(
         check_ok!(
-            name_seg().parse(&[b'A', b'F', b'3', b'Z', 0xff]),
+            name_seg().parse(&[b'A', b'F', b'3', b'Z', 0xff], &mut context),
             NameSeg([b'A', b'F', b'3', b'Z']),
             NameSeg([b'A', b'F', b'3', b'Z']),
             &[0xff]
             &[0xff]
         );
         );
         check_err!(
         check_err!(
-            name_seg().parse(&[0xff, b'E', b'A', b'7']),
+            name_seg().parse(&[0xff, b'E', b'A', b'7'], &mut context),
             AmlError::UnexpectedByte(0xff),
             AmlError::UnexpectedByte(0xff),
             &[0xff, b'E', b'A', b'7']
             &[0xff, b'E', b'A', b'7']
         );
         );
-        check_err!(name_seg().parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
+        check_err!(name_seg().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
     }
     }
 
 
     #[test]
     #[test]
     fn test_name_path() {
     fn test_name_path() {
-        check_err!(name_path().parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
-        check_ok!(name_path().parse(&[0x00]), String::from(""), &[]);
-        check_ok!(name_path().parse(&[0x00, 0x00]), String::from(""), &[0x00]);
+        let mut context = AmlContext::new();
+
+        check_err!(name_path().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
+        check_ok!(name_path().parse(&[0x00], &mut context), String::from(""), &[]);
+        check_ok!(name_path().parse(&[0x00, 0x00], &mut context), String::from(""), &[0x00]);
         // TODO: this failure is actually a symptom of `choice!` not working quite correctly. When
         // TODO: this failure is actually a symptom of `choice!` not working quite correctly. When
         // the dual_name_path parser fails (this is one, but is too short), it carries on and then
         // the dual_name_path parser fails (this is one, but is too short), it carries on and then
         // returns a confusing error: `UnexpectedByte(0x2e)`. Not sure how the best way to go about
         // returns a confusing error: `UnexpectedByte(0x2e)`. Not sure how the best way to go about
@@ -152,14 +180,15 @@ mod tests {
         //
         //
         // For now, we know about this corner case, so altering the unit-test for now.
         // For now, we know about this corner case, so altering the unit-test for now.
         check_err!(
         check_err!(
-            name_path().parse(&[0x2e, b'A']),
+            name_path().parse(&[0x2e, b'A'], &mut context),
             AmlError::UnexpectedByte(0x2e),
             AmlError::UnexpectedByte(0x2e),
             // TODO: this is the correct error
             // TODO: this is the correct error
             // AmlError::UnexpectedEndOfStream,
             // AmlError::UnexpectedEndOfStream,
             &[0x2e, b'A']
             &[0x2e, b'A']
         );
         );
         check_ok!(
         check_ok!(
-            name_path().parse(&[0x2e, b'A', b'B', b'C', b'D', b'E', b'_', b'F', b'G']),
+            name_path()
+                .parse(&[0x2e, b'A', b'B', b'C', b'D', b'E', b'_', b'F', b'G'], &mut context),
             String::from("ABCDE_FG"),
             String::from("ABCDE_FG"),
             &[]
             &[]
         );
         );

+ 38 - 13
aml_parser/src/opcode.rs

@@ -1,4 +1,4 @@
-use crate::{parser::*, AmlError};
+use crate::{parser::*, AmlContext, AmlError};
 
 
 pub const NULL_NAME: u8 = 0x00;
 pub const NULL_NAME: u8 = 0x00;
 pub const DUAL_NAME_PREFIX: u8 = 0x2E;
 pub const DUAL_NAME_PREFIX: u8 = 0x2E;
@@ -32,15 +32,21 @@ pub const EXT_DEVICE_OP: u8 = 0x82;
 
 
 pub const EXT_OPCODE_PREFIX: u8 = 0x5b;
 pub const EXT_OPCODE_PREFIX: u8 = 0x5b;
 
 
-pub(crate) fn opcode<'a>(opcode: u8) -> impl Parser<'a, ()> {
-    move |stream: &'a [u8]| match stream.first() {
-        None => Err((stream, AmlError::UnexpectedEndOfStream)),
-        Some(&byte) if byte == opcode => Ok((&stream[1..], ())),
-        Some(&byte) => Err((stream, AmlError::UnexpectedByte(byte))),
+pub(crate) fn opcode<'a, 'c>(opcode: u8) -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| match input.first() {
+        None => Err((input, context, AmlError::UnexpectedEndOfStream)),
+        Some(&byte) if byte == opcode => Ok((&input[1..], context, ())),
+        Some(&byte) => Err((input, context, AmlError::UnexpectedByte(byte))),
     }
     }
 }
 }
 
 
-pub(crate) fn ext_opcode<'a>(ext_opcode: u8) -> impl Parser<'a, ()> {
+pub(crate) fn ext_opcode<'a, 'c>(ext_opcode: u8) -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     opcode(EXT_OPCODE_PREFIX).then(opcode(ext_opcode)).map(|_| ())
     opcode(EXT_OPCODE_PREFIX).then(opcode(ext_opcode)).map(|_| ())
 }
 }
 
 
@@ -51,23 +57,42 @@ mod tests {
 
 
     #[test]
     #[test]
     fn empty() {
     fn empty() {
-        check_err!(opcode(NULL_NAME).parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
-        check_err!(ext_opcode(EXT_FIELD_OP).parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
+        let mut context = AmlContext::new();
+        check_err!(
+            opcode(NULL_NAME).parse(&[], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[]
+        );
+        check_err!(
+            ext_opcode(EXT_FIELD_OP).parse(&[], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[]
+        );
     }
     }
 
 
     #[test]
     #[test]
     fn simple_opcodes() {
     fn simple_opcodes() {
-        check_ok!(opcode(SCOPE_OP).parse(&[SCOPE_OP]), (), &[]);
-        check_ok!(opcode(NAME_OP).parse(&[NAME_OP, 0x31, 0x55, 0xf3]), (), &[0x31, 0x55, 0xf3]);
+        let mut context = AmlContext::new();
+        check_ok!(opcode(SCOPE_OP).parse(&[SCOPE_OP], &mut context), (), &[]);
+        check_ok!(
+            opcode(NAME_OP).parse(&[NAME_OP, 0x31, 0x55, 0xf3], &mut context),
+            (),
+            &[0x31, 0x55, 0xf3]
+        );
     }
     }
 
 
     #[test]
     #[test]
     fn extended_opcodes() {
     fn extended_opcodes() {
+        let mut context = AmlContext::new();
         check_err!(
         check_err!(
-            ext_opcode(EXT_FIELD_OP).parse(&[EXT_FIELD_OP, EXT_FIELD_OP]),
+            ext_opcode(EXT_FIELD_OP).parse(&[EXT_FIELD_OP, EXT_FIELD_OP], &mut context),
             AmlError::UnexpectedByte(EXT_FIELD_OP),
             AmlError::UnexpectedByte(EXT_FIELD_OP),
             &[EXT_FIELD_OP, EXT_FIELD_OP]
             &[EXT_FIELD_OP, EXT_FIELD_OP]
         );
         );
-        check_ok!(ext_opcode(EXT_FIELD_OP).parse(&[EXT_OPCODE_PREFIX, EXT_FIELD_OP]), (), &[]);
+        check_ok!(
+            ext_opcode(EXT_FIELD_OP).parse(&[EXT_OPCODE_PREFIX, EXT_FIELD_OP], &mut context),
+            (),
+            &[]
+        );
     }
     }
 }
 }

+ 178 - 113
aml_parser/src/parser.rs

@@ -1,37 +1,41 @@
-use crate::AmlError;
+use crate::{AmlContext, AmlError};
 use alloc::vec::Vec;
 use alloc::vec::Vec;
 use core::marker::PhantomData;
 use core::marker::PhantomData;
 use log::trace;
 use log::trace;
 
 
-pub type ParseResult<'a, R> = Result<(&'a [u8], R), (&'a [u8], AmlError)>;
+pub type ParseResult<'a, 'c, R> =
+    Result<(&'a [u8], &'c mut AmlContext, R), (&'a [u8], &'c mut AmlContext, AmlError)>;
 
 
-pub trait Parser<'a, R>: Sized {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, R>;
+pub trait Parser<'a, 'c, R>: Sized
+where
+    'c: 'a,
+{
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, R>;
 
 
-    fn map<F, A>(self, map_fn: F) -> Map<'a, Self, F, R, A>
+    fn map<F, A>(self, map_fn: F) -> Map<'a, 'c, Self, F, R, A>
     where
     where
         F: Fn(R) -> A,
         F: Fn(R) -> A,
     {
     {
         Map { parser: self, map_fn, _phantom: PhantomData }
         Map { parser: self, map_fn, _phantom: PhantomData }
     }
     }
 
 
-    fn discard_result(self) -> DiscardResult<'a, Self, R> {
+    fn discard_result(self) -> DiscardResult<'a, 'c, Self, R> {
         DiscardResult { parser: self, _phantom: PhantomData }
         DiscardResult { parser: self, _phantom: PhantomData }
     }
     }
 
 
     /// Try parsing with `self`. If it fails, try parsing with `other`, returning the result of the
     /// Try parsing with `self`. If it fails, try parsing with `other`, returning the result of the
     /// first of the two parsers to succeed. To `or` multiple parsers ergonomically, see the
     /// first of the two parsers to succeed. To `or` multiple parsers ergonomically, see the
     /// `choice!` macro.
     /// `choice!` macro.
-    fn or<OtherParser>(self, other: OtherParser) -> Or<'a, Self, OtherParser, R>
+    fn or<OtherParser>(self, other: OtherParser) -> Or<'a, 'c, Self, OtherParser, R>
     where
     where
-        OtherParser: Parser<'a, R>,
+        OtherParser: Parser<'a, 'c, R>,
     {
     {
         Or { p1: self, p2: other, _phantom: PhantomData }
         Or { p1: self, p2: other, _phantom: PhantomData }
     }
     }
 
 
-    fn then<NextParser, NextR>(self, next: NextParser) -> Then<'a, Self, NextParser, R, NextR>
+    fn then<NextParser, NextR>(self, next: NextParser) -> Then<'a, 'c, Self, NextParser, R, NextR>
     where
     where
-        NextParser: Parser<'a, NextR>,
+        NextParser: Parser<'a, 'c, NextR>,
     {
     {
         Then { p1: self, p2: next, _phantom: PhantomData }
         Then { p1: self, p2: next, _phantom: PhantomData }
     }
     }
@@ -41,49 +45,60 @@ pub trait Parser<'a, R>: Sized {
     /// but is useful for when the next parser's behaviour depends on a property of the result of
     /// but is useful for when the next parser's behaviour depends on a property of the result of
     /// the first (e.g. the first parser might parse a length `n`, and the second parser then
     /// the first (e.g. the first parser might parse a length `n`, and the second parser then
     /// consumes `n` bytes).
     /// consumes `n` bytes).
-    fn feed<F, P2, R2>(self, producer_fn: F) -> Feed<'a, Self, P2, F, R, R2>
+    fn feed<F, P2, R2>(self, producer_fn: F) -> Feed<'a, 'c, Self, P2, F, R, R2>
     where
     where
-        P2: Parser<'a, R2>,
+        P2: Parser<'a, 'c, R2>,
         F: Fn(R) -> P2,
         F: Fn(R) -> P2,
     {
     {
         Feed { parser: self, producer_fn, _phantom: PhantomData }
         Feed { parser: self, producer_fn, _phantom: PhantomData }
     }
     }
 }
 }
 
 
-impl<'a, F, R> Parser<'a, R> for F
+impl<'a, 'c, F, R> Parser<'a, 'c, R> for F
 where
 where
-    F: Fn(&'a [u8]) -> ParseResult<'a, R>,
+    'c: 'a,
+    F: Fn(&'a [u8], &'c mut AmlContext) -> ParseResult<'a, 'c, R>,
 {
 {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, R> {
-        self(input)
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, R> {
+        self(input, context)
     }
     }
 }
 }
 
 
-pub fn take<'a>() -> impl Parser<'a, u8> {
-    move |input: &'a [u8]| match input.first() {
-        Some(&byte) => Ok((&input[1..], byte)),
-        None => Err((input, AmlError::UnexpectedEndOfStream)),
+pub fn take<'a, 'c>() -> impl Parser<'a, 'c, u8>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| match input.first() {
+        Some(&byte) => Ok((&input[1..], context, byte)),
+        None => Err((input, context, AmlError::UnexpectedEndOfStream)),
     }
     }
 }
 }
 
 
-pub fn take_u16<'a>() -> impl Parser<'a, u16> {
-    move |input: &'a [u8]| {
+pub fn take_u16<'a, 'c>() -> impl Parser<'a, 'c, u16>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| {
         if input.len() < 2 {
         if input.len() < 2 {
-            return Err((input, AmlError::UnexpectedEndOfStream));
+            return Err((input, context, AmlError::UnexpectedEndOfStream));
         }
         }
 
 
-        Ok((&input[2..], input[0] as u16 + ((input[1] as u16) << 8)))
+        Ok((&input[2..], context, input[0] as u16 + ((input[1] as u16) << 8)))
     }
     }
 }
 }
 
 
-pub fn take_u32<'a>() -> impl Parser<'a, u32> {
-    move |input: &'a [u8]| {
+pub fn take_u32<'a, 'c>() -> impl Parser<'a, 'c, u32>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| {
         if input.len() < 4 {
         if input.len() < 4 {
-            return Err((input, AmlError::UnexpectedEndOfStream));
+            return Err((input, context, AmlError::UnexpectedEndOfStream));
         }
         }
 
 
         Ok((
         Ok((
             &input[4..],
             &input[4..],
+            context,
             input[0] as u32
             input[0] as u32
                 + ((input[1] as u32) << 8)
                 + ((input[1] as u32) << 8)
                 + ((input[2] as u32) << 16)
                 + ((input[2] as u32) << 16)
@@ -92,14 +107,18 @@ pub fn take_u32<'a>() -> impl Parser<'a, u32> {
     }
     }
 }
 }
 
 
-pub fn take_u64<'a>() -> impl Parser<'a, u64> {
-    move |input: &'a [u8]| {
+pub fn take_u64<'a, 'c>() -> impl Parser<'a, 'c, u64>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| {
         if input.len() < 8 {
         if input.len() < 8 {
-            return Err((input, AmlError::UnexpectedEndOfStream));
+            return Err((input, context, AmlError::UnexpectedEndOfStream));
         }
         }
 
 
         Ok((
         Ok((
             &input[8..],
             &input[8..],
+            context,
             input[0] as u64
             input[0] as u64
                 + ((input[1] as u64) << 8)
                 + ((input[1] as u64) << 8)
                 + ((input[2] as u64) << 16)
                 + ((input[2] as u64) << 16)
@@ -112,178 +131,201 @@ pub fn take_u64<'a>() -> impl Parser<'a, u64> {
     }
     }
 }
 }
 
 
-pub fn take_n<'a>(n: usize) -> impl Parser<'a, &'a [u8]> {
-    move |input: &'a [u8]| {
+pub fn take_n<'a, 'c>(n: usize) -> impl Parser<'a, 'c, &'a [u8]>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context| {
         if input.len() < n {
         if input.len() < n {
-            return Err((input, AmlError::UnexpectedEndOfStream));
+            return Err((input, context, AmlError::UnexpectedEndOfStream));
         }
         }
 
 
         let (result, new_input) = input.split_at(n);
         let (result, new_input) = input.split_at(n);
-        Ok((new_input, result))
+        Ok((new_input, context, result))
     }
     }
 }
 }
 
 
 // TODO: can we use const generics (e.g. [R; N]) to avoid allocating?
 // TODO: can we use const generics (e.g. [R; N]) to avoid allocating?
-pub fn n_of<'a, P, R>(parser: P, n: usize) -> impl Parser<'a, Vec<R>>
+pub fn n_of<'a, 'c, P, R>(parser: P, n: usize) -> impl Parser<'a, 'c, Vec<R>>
 where
 where
-    P: Parser<'a, R>,
+    'c: 'a,
+    P: Parser<'a, 'c, R>,
 {
 {
-    move |input| {
+    // TODO: can we write this more nicely?
+    move |mut input, mut context| {
         let mut results = Vec::with_capacity(n);
         let mut results = Vec::with_capacity(n);
-        let mut new_input = input;
 
 
         for _ in 0..n {
         for _ in 0..n {
-            let (after_input, result) = match parser.parse(new_input) {
-                Ok((input, result)) => (input, result),
-                Err((_, err)) => return Err((input, err)),
+            let (new_input, new_context, result) = match parser.parse(input, context) {
+                Ok((input, context, result)) => (input, context, result),
+                Err((_, context, err)) => return Err((input, context, err)),
             };
             };
             results.push(result);
             results.push(result);
-            new_input = after_input;
+            input = new_input;
+            context = new_context;
         }
         }
 
 
-        Ok((new_input, results))
+        Ok((input, context, results))
     }
     }
 }
 }
 
 
-pub fn consume<'a, F>(condition: F) -> impl Parser<'a, u8>
+pub fn consume<'a, 'c, F>(condition: F) -> impl Parser<'a, 'c, u8>
 where
 where
+    'c: 'a,
     F: Fn(u8) -> bool,
     F: Fn(u8) -> bool,
 {
 {
-    move |input: &'a [u8]| match input.first() {
-        Some(&byte) if condition(byte) => Ok((&input[1..], byte)),
-        Some(&byte) => Err((input, AmlError::UnexpectedByte(byte))),
-        None => Err((input, AmlError::UnexpectedEndOfStream)),
+    move |input: &'a [u8], context: &'c mut AmlContext| match input.first() {
+        Some(&byte) if condition(byte) => Ok((&input[1..], context, byte)),
+        Some(&byte) => Err((input, context, AmlError::UnexpectedByte(byte))),
+        None => Err((input, context, AmlError::UnexpectedEndOfStream)),
     }
     }
 }
 }
 
 
-pub fn comment_scope<'a, P, R>(scope_name: &'a str, parser: P) -> impl Parser<'a, R>
+pub fn comment_scope<'a, 'c, P, R>(scope_name: &'a str, parser: P) -> impl Parser<'a, 'c, R>
 where
 where
+    'c: 'a,
     R: core::fmt::Debug,
     R: core::fmt::Debug,
-    P: Parser<'a, R>,
+    P: Parser<'a, 'c, R>,
 {
 {
-    move |input| {
+    move |input, context| {
         trace!("--> {}", scope_name);
         trace!("--> {}", scope_name);
         // Return if the parse fails, so we don't print the tail. Makes it easier to debug.
         // Return if the parse fails, so we don't print the tail. Makes it easier to debug.
-        let (new_input, result) = parser.parse(input)?;
+        let (new_input, context, result) = parser.parse(input, context)?;
         trace!("<-- {}({:?})", scope_name, result);
         trace!("<-- {}({:?})", scope_name, result);
-        Ok((new_input, result))
+        Ok((new_input, context, result))
     }
     }
 }
 }
 
 
-pub struct Or<'a, P1, P2, R>
+pub struct Or<'a, 'c, P1, P2, R>
 where
 where
-    P1: Parser<'a, R>,
-    P2: Parser<'a, R>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R>,
+    P2: Parser<'a, 'c, R>,
 {
 {
     p1: P1,
     p1: P1,
     p2: P2,
     p2: P2,
-    _phantom: PhantomData<&'a R>,
+    _phantom: PhantomData<(&'a R, &'c ())>,
 }
 }
 
 
-impl<'a, P1, P2, R> Parser<'a, R> for Or<'a, P1, P2, R>
+impl<'a, 'c, P1, P2, R> Parser<'a, 'c, R> for Or<'a, 'c, P1, P2, R>
 where
 where
-    P1: Parser<'a, R>,
-    P2: Parser<'a, R>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R>,
+    P2: Parser<'a, 'c, R>,
 {
 {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, R> {
-        match self.p1.parse(input) {
-            Ok(result) => return Ok(result),
-            Err(_) => (),
-        }
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, R> {
+        let context = match self.p1.parse(input, context) {
+            Ok(parse_result) => return Ok(parse_result),
+            Err((_, context, _)) => context,
+        };
 
 
-        self.p2.parse(input)
+        self.p2.parse(input, context)
     }
     }
 }
 }
 
 
-pub struct Map<'a, P, F, R, A>
+pub struct Map<'a, 'c, P, F, R, A>
 where
 where
-    P: Parser<'a, R>,
+    'c: 'a,
+    P: Parser<'a, 'c, R>,
     F: Fn(R) -> A,
     F: Fn(R) -> A,
 {
 {
     parser: P,
     parser: P,
     map_fn: F,
     map_fn: F,
-    _phantom: PhantomData<&'a (R, A)>,
+    _phantom: PhantomData<(&'a (R, A), &'c ())>,
 }
 }
 
 
-impl<'a, P, F, R, A> Parser<'a, A> for Map<'a, P, F, R, A>
+impl<'a, 'c, P, F, R, A> Parser<'a, 'c, A> for Map<'a, 'c, P, F, R, A>
 where
 where
-    P: Parser<'a, R>,
+    'c: 'a,
+    P: Parser<'a, 'c, R>,
     F: Fn(R) -> A,
     F: Fn(R) -> A,
 {
 {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, A> {
-        self.parser.parse(input).map(|(new_input, result)| (new_input, (self.map_fn)(result)))
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, A> {
+        self.parser
+            .parse(input, context)
+            .map(|(new_input, new_context, result)| (new_input, new_context, (self.map_fn)(result)))
     }
     }
 }
 }
 
 
-pub struct DiscardResult<'a, P, R>
+pub struct DiscardResult<'a, 'c, P, R>
 where
 where
-    P: Parser<'a, R>,
+    'c: 'a,
+    P: Parser<'a, 'c, R>,
 {
 {
     parser: P,
     parser: P,
-    _phantom: PhantomData<&'a R>,
+    _phantom: PhantomData<(&'a R, &'c ())>,
 }
 }
 
 
-impl<'a, P, R> Parser<'a, ()> for DiscardResult<'a, P, R>
+impl<'a, 'c, P, R> Parser<'a, 'c, ()> for DiscardResult<'a, 'c, P, R>
 where
 where
-    P: Parser<'a, R>,
+    'c: 'a,
+    P: Parser<'a, 'c, R>,
 {
 {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, ()> {
-        self.parser.parse(input).map(|(new_input, _)| (new_input, ()))
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, ()> {
+        self.parser
+            .parse(input, context)
+            .map(|(new_input, new_context, _)| (new_input, new_context, ()))
     }
     }
 }
 }
 
 
-pub struct Then<'a, P1, P2, R1, R2>
+pub struct Then<'a, 'c, P1, P2, R1, R2>
 where
 where
-    P1: Parser<'a, R1>,
-    P2: Parser<'a, R2>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R1>,
+    P2: Parser<'a, 'c, R2>,
 {
 {
     p1: P1,
     p1: P1,
     p2: P2,
     p2: P2,
-    _phantom: PhantomData<&'a (R1, R2)>,
+    _phantom: PhantomData<(&'a (R1, R2), &'c ())>,
 }
 }
 
 
-impl<'a, P1, P2, R1, R2> Parser<'a, (R1, R2)> for Then<'a, P1, P2, R1, R2>
+impl<'a, 'c, P1, P2, R1, R2> Parser<'a, 'c, (R1, R2)> for Then<'a, 'c, P1, P2, R1, R2>
 where
 where
-    P1: Parser<'a, R1>,
-    P2: Parser<'a, R2>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R1>,
+    P2: Parser<'a, 'c, 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)))
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, (R1, R2)> {
+        self.p1.parse(input, context).and_then(|(next_input, context, result_a)| {
+            self.p2.parse(next_input, context).map(|(final_input, context, result_b)| {
+                (final_input, context, (result_a, result_b))
+            })
         })
         })
     }
     }
 }
 }
 
 
-pub struct Feed<'a, P1, P2, F, R1, R2>
+pub struct Feed<'a, 'c, P1, P2, F, R1, R2>
 where
 where
-    P1: Parser<'a, R1>,
-    P2: Parser<'a, R2>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R1>,
+    P2: Parser<'a, 'c, R2>,
     F: Fn(R1) -> P2,
     F: Fn(R1) -> P2,
 {
 {
     parser: P1,
     parser: P1,
     producer_fn: F,
     producer_fn: F,
-    _phantom: PhantomData<&'a (R1, R2)>,
+    _phantom: PhantomData<(&'a (R1, R2), &'c ())>,
 }
 }
 
 
-impl<'a, P1, P2, F, R1, R2> Parser<'a, R2> for Feed<'a, P1, P2, F, R1, R2>
+impl<'a, 'c, P1, P2, F, R1, R2> Parser<'a, 'c, R2> for Feed<'a, 'c, P1, P2, F, R1, R2>
 where
 where
-    P1: Parser<'a, R1>,
-    P2: Parser<'a, R2>,
+    'c: 'a,
+    P1: Parser<'a, 'c, R1>,
+    P2: Parser<'a, 'c, R2>,
     F: Fn(R1) -> P2,
     F: Fn(R1) -> P2,
 {
 {
-    fn parse(&self, input: &'a [u8]) -> ParseResult<'a, R2> {
-        let (input, first_result) = self.parser.parse(input)?;
+    fn parse(&self, input: &'a [u8], context: &'c mut AmlContext) -> ParseResult<'a, 'c, R2> {
+        let (input, context, first_result) = self.parser.parse(input, context)?;
 
 
         // We can now produce the second parser, and parse using that.
         // We can now produce the second parser, and parse using that.
         let second_parser = (self.producer_fn)(first_result);
         let second_parser = (self.producer_fn)(first_result);
-        second_parser.parse(input)
+        second_parser.parse(input, context)
     }
     }
 }
 }
 
 
 /// Takes a number of parsers, and tries to apply each one to the input in order. Returns the
 /// 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.
 /// result of the first one that succeeds, or fails if all of them fail.
+// TODO: maybe this should emit a custom error at the end? "None of these parsers could parse
+// this?" Or maybe just a specific UnexpectedByte?
 pub macro choice {
 pub macro choice {
     ($first_parser: expr) => {
     ($first_parser: expr) => {
         $first_parser
         $first_parser
@@ -304,25 +346,48 @@ mod tests {
 
 
     #[test]
     #[test]
     fn test_take_n() {
     fn test_take_n() {
-        check_err!(take_n(1).parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
-        check_err!(take_n(2).parse(&[0xf5]), AmlError::UnexpectedEndOfStream, &[0xf5]);
+        let mut context = AmlContext::new();
+        check_err!(take_n(1).parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
+        check_err!(
+            take_n(2).parse(&[0xf5], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[0xf5]
+        );
 
 
-        check_ok!(take_n(1).parse(&[0xff]), &[0xff], &[]);
-        check_ok!(take_n(1).parse(&[0xff, 0xf8]), &[0xff], &[0xf8]);
-        check_ok!(take_n(2).parse(&[0xff, 0xf8]), &[0xff, 0xf8], &[]);
+        check_ok!(take_n(1).parse(&[0xff], &mut context), &[0xff], &[]);
+        check_ok!(take_n(1).parse(&[0xff, 0xf8], &mut context), &[0xff], &[0xf8]);
+        check_ok!(take_n(2).parse(&[0xff, 0xf8], &mut context), &[0xff, 0xf8], &[]);
     }
     }
 
 
     #[test]
     #[test]
     fn test_take_ux() {
     fn test_take_ux() {
-        check_err!(take_u16().parse(&[0x34]), AmlError::UnexpectedEndOfStream, &[0x34]);
-        check_ok!(take_u16().parse(&[0x34, 0x12]), 0x1234, &[]);
+        let mut context = AmlContext::new();
+        check_err!(
+            take_u16().parse(&[0x34], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[0x34]
+        );
+        check_ok!(take_u16().parse(&[0x34, 0x12], &mut context), 0x1234, &[]);
 
 
-        check_err!(take_u32().parse(&[0x34, 0x12]), AmlError::UnexpectedEndOfStream, &[0x34, 0x12]);
-        check_ok!(take_u32().parse(&[0x34, 0x12, 0xf4, 0xc3, 0x3e]), 0xc3f41234, &[0x3e]);
+        check_err!(
+            take_u32().parse(&[0x34, 0x12], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[0x34, 0x12]
+        );
+        check_ok!(
+            take_u32().parse(&[0x34, 0x12, 0xf4, 0xc3, 0x3e], &mut context),
+            0xc3f41234,
+            &[0x3e]
+        );
 
 
-        check_err!(take_u64().parse(&[0x34]), AmlError::UnexpectedEndOfStream, &[0x34]);
+        check_err!(
+            take_u64().parse(&[0x34], &mut context),
+            AmlError::UnexpectedEndOfStream,
+            &[0x34]
+        );
         check_ok!(
         check_ok!(
-            take_u64().parse(&[0x34, 0x12, 0x35, 0x76, 0xd4, 0x43, 0xa3, 0xb6, 0xff, 0x00]),
+            take_u64()
+                .parse(&[0x34, 0x12, 0x35, 0x76, 0xd4, 0x43, 0xa3, 0xb6, 0xff, 0x00], &mut context),
             0xb6a343d476351234,
             0xb6a343d476351234,
             &[0xff, 0x00]
             &[0xff, 0x00]
         );
         );

+ 45 - 31
aml_parser/src/pkg_length.rs

@@ -1,5 +1,6 @@
 use crate::{
 use crate::{
     parser::{take, take_n, Parser},
     parser::{take, take_n, Parser},
+    AmlContext,
     AmlError,
     AmlError,
 };
 };
 use bit_field::BitField;
 use bit_field::BitField;
@@ -24,21 +25,27 @@ impl PkgLength {
     }
     }
 }
 }
 
 
-pub fn pkg_length<'a>() -> impl Parser<'a, PkgLength> {
-    move |input: &'a [u8]| {
-        let (new_input, raw_length) = raw_pkg_length().parse(input)?;
+pub fn pkg_length<'a, 'c>() -> impl Parser<'a, 'c, PkgLength>
+where
+    'c: 'a,
+{
+    move |input: &'a [u8], context: &'c mut AmlContext| {
+        let (new_input, context, raw_length) = raw_pkg_length().parse(input, context)?;
 
 
         /*
         /*
          * NOTE: we use the original input here, because `raw_length` includes the length of the
          * NOTE: we use the original input here, because `raw_length` includes the length of the
          * `PkgLength`.
          * `PkgLength`.
          */
          */
-        Ok((new_input, PkgLength::from_raw_length(input, raw_length)))
+        Ok((new_input, context, PkgLength::from_raw_length(input, raw_length)))
     }
     }
 }
 }
 
 
 /// Parses a `PkgLength` and returns the *raw length*. If you want an instance of `PkgLength`, use
 /// Parses a `PkgLength` and returns the *raw length*. If you want an instance of `PkgLength`, use
 /// `pkg_length` instead.
 /// `pkg_length` instead.
-pub fn raw_pkg_length<'a>() -> impl Parser<'a, u32> {
+pub fn raw_pkg_length<'a, 'c>() -> impl Parser<'a, 'c, u32>
+where
+    'c: 'a,
+{
     /*
     /*
      * PkgLength := PkgLeadByte |
      * PkgLength := PkgLeadByte |
      * <PkgLeadByte ByteData> |
      * <PkgLeadByte ByteData> |
@@ -47,34 +54,38 @@ pub fn raw_pkg_length<'a>() -> impl Parser<'a, u32> {
      *
      *
      * The length encoded by the PkgLength includes the number of bytes used to encode it.
      * The length encoded by the PkgLength includes the number of bytes used to encode it.
      */
      */
-    move |input: &'a [u8]| {
-        let (new_input, lead_byte) = take().parse(input)?;
+    move |input: &'a [u8], context: &'c mut AmlContext| {
+        let (new_input, context, lead_byte) = take().parse(input, context)?;
         let byte_count = lead_byte.get_bits(6..8);
         let byte_count = lead_byte.get_bits(6..8);
 
 
         if byte_count == 0 {
         if byte_count == 0 {
             let length = u32::from(lead_byte.get_bits(0..6));
             let length = u32::from(lead_byte.get_bits(0..6));
-            return Ok((new_input, length));
+            return Ok((new_input, context, length));
         }
         }
 
 
-        let (new_input, length): (&[u8], u32) = match take_n(byte_count as usize).parse(new_input) {
-            Ok((new_input, bytes)) => {
-                let initial_length = u32::from(lead_byte.get_bits(0..4));
-                (
-                    new_input,
-                    bytes.iter().enumerate().fold(initial_length, |length, (i, &byte)| {
-                        length + (u32::from(byte) << (4 + i * 8))
-                    }),
-                )
-            }
+        let (new_input, context, length): (&[u8], &mut AmlContext, u32) =
+            match take_n(byte_count as usize).parse(new_input, context) {
+                Ok((new_input, context, bytes)) => {
+                    let initial_length = u32::from(lead_byte.get_bits(0..4));
+                    (
+                        new_input,
+                        context,
+                        bytes.iter().enumerate().fold(initial_length, |length, (i, &byte)| {
+                            length + (u32::from(byte) << (4 + i * 8))
+                        }),
+                    )
+                }
 
 
-            /*
-             * The stream was too short. We return an error, making sure to return the
-             * *original* stream (that we haven't consumed any of).
-             */
-            Err(_) => return Err((input, AmlError::UnexpectedEndOfStream)),
-        };
+                /*
+                 * The stream was too short. We return an error, making sure to return the
+                 * *original* stream (that we haven't consumed any of).
+                 */
+                Err((_, context, _)) => {
+                    return Err((input, context, AmlError::UnexpectedEndOfStream))
+                }
+            };
 
 
-        Ok((new_input, length))
+        Ok((new_input, context, length))
     }
     }
 }
 }
 
 
@@ -84,8 +95,9 @@ mod tests {
     use crate::{test_utils::*, AmlError};
     use crate::{test_utils::*, AmlError};
 
 
     fn test_correct_pkglength(stream: &[u8], expected_raw_length: u32, expected_leftover: &[u8]) {
     fn test_correct_pkglength(stream: &[u8], expected_raw_length: u32, expected_leftover: &[u8]) {
+        let mut context = AmlContext::new();
         check_ok!(
         check_ok!(
-            pkg_length().parse(stream),
+            pkg_length().parse(stream, &mut context),
             PkgLength::from_raw_length(stream, expected_raw_length),
             PkgLength::from_raw_length(stream, expected_raw_length),
             &expected_leftover
             &expected_leftover
         );
         );
@@ -93,14 +105,16 @@ mod tests {
 
 
     #[test]
     #[test]
     fn test_raw_pkg_length() {
     fn test_raw_pkg_length() {
-        check_ok!(raw_pkg_length().parse(&[0b01000101, 0x14]), 325, &[]);
-        check_ok!(raw_pkg_length().parse(&[0b01000111, 0x14, 0x46]), 327, &[0x46]);
-        check_ok!(raw_pkg_length().parse(&[0b10000111, 0x14, 0x46]), 287047, &[]);
+        let mut context = AmlContext::new();
+        check_ok!(raw_pkg_length().parse(&[0b01000101, 0x14], &mut context), 325, &[]);
+        check_ok!(raw_pkg_length().parse(&[0b01000111, 0x14, 0x46], &mut context), 327, &[0x46]);
+        check_ok!(raw_pkg_length().parse(&[0b10000111, 0x14, 0x46], &mut context), 287047, &[]);
     }
     }
 
 
     #[test]
     #[test]
     fn test_pkg_length() {
     fn test_pkg_length() {
-        check_err!(pkg_length().parse(&[]), AmlError::UnexpectedEndOfStream, &[]);
+        let mut context = AmlContext::new();
+        check_err!(pkg_length().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
         test_correct_pkglength(&[0x00], 0, &[]);
         test_correct_pkglength(&[0x00], 0, &[]);
         test_correct_pkglength(
         test_correct_pkglength(
             &[0x05, 0xf5, 0x7f, 0x3e, 0x54, 0x03],
             &[0x05, 0xf5, 0x7f, 0x3e, 0x54, 0x03],
@@ -108,7 +122,7 @@ mod tests {
             &[0xf5, 0x7f, 0x3e, 0x54, 0x03],
             &[0xf5, 0x7f, 0x3e, 0x54, 0x03],
         );
         );
         check_err!(
         check_err!(
-            pkg_length().parse(&[0b11000000, 0xff, 0x4f]),
+            pkg_length().parse(&[0b11000000, 0xff, 0x4f], &mut context),
             AmlError::UnexpectedEndOfStream,
             AmlError::UnexpectedEndOfStream,
             &[0b11000000, 0xff, 0x4f]
             &[0b11000000, 0xff, 0x4f]
         );
         );

+ 72 - 34
aml_parser/src/term_object.rs

@@ -4,6 +4,7 @@ use crate::{
     parser::{choice, comment_scope, take, take_u16, take_u32, take_u64, ParseResult, Parser},
     parser::{choice, comment_scope, take, take_u16, take_u32, take_u64, ParseResult, Parser},
     pkg_length::{pkg_length, PkgLength},
     pkg_length::{pkg_length, PkgLength},
     value::{AmlValue, FieldFlags},
     value::{AmlValue, FieldFlags},
+    AmlContext,
     AmlError,
     AmlError,
 };
 };
 use alloc::string::String;
 use alloc::string::String;
@@ -11,22 +12,29 @@ use log::{debug, trace};
 
 
 /// `TermList`s are usually found within explicit-length objects (so they have a `PkgLength`
 /// `TermList`s are usually found within explicit-length objects (so they have a `PkgLength`
 /// elsewhere in the structure), so this takes a number of bytes to parse.
 /// elsewhere in the structure), so this takes a number of bytes to parse.
-pub fn term_list<'a>(list_length: PkgLength) -> impl Parser<'a, ()> {
+pub fn term_list<'a, 'c>(list_length: PkgLength) -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * TermList := Nothing | <TermObj TermList>
      * TermList := Nothing | <TermObj TermList>
      */
      */
-    move |mut input: &'a [u8]| -> ParseResult<'a, ()> {
+    move |mut input: &'a [u8], mut context: &'c mut AmlContext| {
         while list_length.still_parsing(input) {
         while list_length.still_parsing(input) {
-            let (new_input, ()) = term_object().parse(input)?;
+            let (new_input, new_context, ()) = term_object().parse(input, context)?;
             input = new_input;
             input = new_input;
+            context = new_context;
         }
         }
 
 
-        Ok((input, ()))
+        Ok((input, context, ()))
     }
     }
 }
 }
 
 
 // TODO: maybe return `AmlValue` on success
 // TODO: maybe return `AmlValue` on success
-pub fn term_object<'a>() -> impl Parser<'a, ()> {
+pub fn term_object<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * TermObj := NamespaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
      * TermObj := NamespaceModifierObj | NamedObj | Type1Opcode | Type2Opcode
      * NamespaceModifierObj := DefAlias | DefName | DefScope
      * NamespaceModifierObj := DefAlias | DefName | DefScope
@@ -34,7 +42,10 @@ pub fn term_object<'a>() -> impl Parser<'a, ()> {
     comment_scope("TermObj", choice!(def_scope(), def_op_region(), def_field()))
     comment_scope("TermObj", choice!(def_scope(), def_op_region(), def_field()))
 }
 }
 
 
-pub fn def_scope<'a>() -> impl Parser<'a, ()> {
+pub fn def_scope<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * DefScope := 0x10 PkgLength NameString TermList
      * DefScope := 0x10 PkgLength NameString TermList
      */
      */
@@ -49,7 +60,10 @@ pub fn def_scope<'a>() -> impl Parser<'a, ()> {
         .discard_result()
         .discard_result()
 }
 }
 
 
-pub fn def_op_region<'a>() -> impl Parser<'a, ()> {
+pub fn def_op_region<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
      * DefOpRegion := ExtOpPrefix 0x80 NameString RegionSpace RegionOffset RegionLen
      * RegionSpace := ByteData (where 0x00      = SystemMemory
      * RegionSpace := ByteData (where 0x00      = SystemMemory
@@ -80,7 +94,10 @@ pub fn def_op_region<'a>() -> impl Parser<'a, ()> {
         .discard_result()
         .discard_result()
 }
 }
 
 
-pub fn def_field<'a>() -> impl Parser<'a, ()> {
+pub fn def_field<'a, 'c>() -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
      * DefField = ExtOpPrefix 0x81 PkgLength NameString FieldFlags FieldList
      * FieldFlags := ByteData
      * FieldFlags := ByteData
@@ -90,18 +107,22 @@ pub fn def_field<'a>() -> impl Parser<'a, ()> {
             "DefField",
             "DefField",
             pkg_length().then(name_string()).then(take()).feed(
             pkg_length().then(name_string()).then(take()).feed(
                 |((list_length, region_name), flags)| {
                 |((list_length, region_name), flags)| {
-                    move |mut input: &'a [u8]| -> ParseResult<'a, ()> {
+                    move |mut input: &'a [u8],
+                          mut context: &'c mut AmlContext|
+                          -> ParseResult<'a, 'c, ()> {
                         /*
                         /*
                          * FieldList := Nothing | <FieldElement FieldList>
                          * FieldList := Nothing | <FieldElement FieldList>
                          */
                          */
                         // TODO: can this pattern be expressed as a combinator
                         // TODO: can this pattern be expressed as a combinator
                         while list_length.still_parsing(input) {
                         while list_length.still_parsing(input) {
-                            let (new_input, ()) =
-                                field_element(&region_name, FieldFlags::new(flags)).parse(input)?;
+                            let (new_input, new_context, ()) =
+                                field_element(&region_name, FieldFlags::new(flags))
+                                    .parse(input, context)?;
                             input = new_input;
                             input = new_input;
+                            context = new_context;
                         }
                         }
 
 
-                        Ok((input, ()))
+                        Ok((input, context, ()))
                     }
                     }
                 },
                 },
             ),
             ),
@@ -109,7 +130,10 @@ pub fn def_field<'a>() -> impl Parser<'a, ()> {
         .discard_result()
         .discard_result()
 }
 }
 
 
-pub fn field_element<'a>(region_name: &String, flags: FieldFlags) -> impl Parser<'a, ()> {
+pub fn field_element<'a, 'c>(region_name: &String, flags: FieldFlags) -> impl Parser<'a, 'c, ()>
+where
+    'c: 'a,
+{
     /*
     /*
      * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
      * FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField |
      *                 ConnectField
      *                 ConnectField
@@ -150,7 +174,10 @@ pub fn field_element<'a>(region_name: &String, flags: FieldFlags) -> impl Parser
     choice!(reserved_field, access_field, named_field)
     choice!(reserved_field, access_field, named_field)
 }
 }
 
 
-pub fn term_arg<'a>() -> impl Parser<'a, AmlValue> {
+pub fn term_arg<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
     /*
     /*
      * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
      * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
      */
      */
@@ -158,7 +185,10 @@ pub fn term_arg<'a>() -> impl Parser<'a, AmlValue> {
     comment_scope("TermArg", choice!(data_object()))
     comment_scope("TermArg", choice!(data_object()))
 }
 }
 
 
-pub fn data_object<'a>() -> impl Parser<'a, AmlValue> {
+pub fn data_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
     /*
     /*
      * DataObject := DefPackage | DefVarPackage | ComputationalData
      * DataObject := DefPackage | DefVarPackage | ComputationalData
      *
      *
@@ -169,7 +199,10 @@ pub fn data_object<'a>() -> impl Parser<'a, AmlValue> {
     comment_scope("DataObject", choice!(computational_data()))
     comment_scope("DataObject", choice!(computational_data()))
 }
 }
 
 
-pub fn computational_data<'a>() -> impl Parser<'a, AmlValue> {
+pub fn computational_data<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
     /*
     /*
      * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |
      * ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String |
      *                      ConstObj | RevisionOp | DefBuffer
      *                      ConstObj | RevisionOp | DefBuffer
@@ -181,28 +214,28 @@ pub fn computational_data<'a>() -> impl Parser<'a, AmlValue> {
      * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff)
      * ConstObj := ZeroOp(0x00) | OneOp(0x01) | OnesOp(0xff)
      * RevisionOp := ExtOpPrefix(0x5b) 0x30
      * RevisionOp := ExtOpPrefix(0x5b) 0x30
      */
      */
-    let const_parser = |input: &'a [u8]| {
-        let (new_input, op) = take().parse(input)?;
+    let const_parser = |input: &'a [u8], context: &'c mut AmlContext| {
+        let (new_input, context, op) = take().parse(input, context)?;
 
 
         match op {
         match op {
             opcode::BYTE_CONST => {
             opcode::BYTE_CONST => {
-                take().map(|value| AmlValue::Integer(value as u64)).parse(new_input)
+                take().map(|value| AmlValue::Integer(value as u64)).parse(new_input, context)
             }
             }
             opcode::WORD_CONST => {
             opcode::WORD_CONST => {
-                take_u16().map(|value| AmlValue::Integer(value as u64)).parse(new_input)
+                take_u16().map(|value| AmlValue::Integer(value as u64)).parse(new_input, context)
             }
             }
             opcode::DWORD_CONST => {
             opcode::DWORD_CONST => {
-                take_u32().map(|value| AmlValue::Integer(value as u64)).parse(new_input)
+                take_u32().map(|value| AmlValue::Integer(value as u64)).parse(new_input, context)
             }
             }
             opcode::QWORD_CONST => {
             opcode::QWORD_CONST => {
-                take_u64().map(|value| AmlValue::Integer(value)).parse(new_input)
+                take_u64().map(|value| AmlValue::Integer(value)).parse(new_input, context)
             }
             }
             // TODO: implement String
             // TODO: implement String
-            opcode::ZERO_OP => Ok((new_input, AmlValue::Integer(0))),
-            opcode::ONE_OP => Ok((new_input, AmlValue::Integer(1))),
-            opcode::ONES_OP => Ok((new_input, AmlValue::Integer(u64::max_value()))),
+            opcode::ZERO_OP => Ok((new_input, context, AmlValue::Integer(0))),
+            opcode::ONE_OP => Ok((new_input, context, AmlValue::Integer(1))),
+            opcode::ONES_OP => Ok((new_input, context, AmlValue::Integer(u64::max_value()))),
 
 
-            _ => Err((input, AmlError::UnexpectedByte(op))),
+            _ => Err((input, context, AmlError::UnexpectedByte(op))),
         }
         }
     };
     };
 
 
@@ -223,40 +256,45 @@ mod test {
 
 
     #[test]
     #[test]
     fn test_computational_data() {
     fn test_computational_data() {
+        let mut context = AmlContext::new();
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0x00, 0x34, 0x12]),
+            computational_data().parse(&[0x00, 0x34, 0x12], &mut context),
             AmlValue::Integer(0),
             AmlValue::Integer(0),
             &[0x34, 0x12]
             &[0x34, 0x12]
         );
         );
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0x01, 0x18, 0xf3]),
+            computational_data().parse(&[0x01, 0x18, 0xf3], &mut context),
             AmlValue::Integer(1),
             AmlValue::Integer(1),
             &[0x18, 0xf3]
             &[0x18, 0xf3]
         );
         );
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0xff, 0x98, 0xc3]),
+            computational_data().parse(&[0xff, 0x98, 0xc3], &mut context),
             AmlValue::Integer(u64::max_value()),
             AmlValue::Integer(u64::max_value()),
             &[0x98, 0xc3]
             &[0x98, 0xc3]
         );
         );
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0x5b, 0x30]),
+            computational_data().parse(&[0x5b, 0x30], &mut context),
             AmlValue::Integer(crate::AML_INTERPRETER_REVISION),
             AmlValue::Integer(crate::AML_INTERPRETER_REVISION),
             &[]
             &[]
         );
         );
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0x0a, 0xf3, 0x35]),
+            computational_data().parse(&[0x0a, 0xf3, 0x35], &mut context),
             AmlValue::Integer(0xf3),
             AmlValue::Integer(0xf3),
             &[0x35]
             &[0x35]
         );
         );
-        check_ok!(computational_data().parse(&[0x0b, 0xf3, 0x35]), AmlValue::Integer(0x35f3), &[]);
         check_ok!(
         check_ok!(
-            computational_data().parse(&[0x0c, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00]),
+            computational_data().parse(&[0x0b, 0xf3, 0x35], &mut context),
+            AmlValue::Integer(0x35f3),
+            &[]
+        );
+        check_ok!(
+            computational_data().parse(&[0x0c, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00], &mut context),
             AmlValue::Integer(0x651235f3),
             AmlValue::Integer(0x651235f3),
             &[0xff, 0x00]
             &[0xff, 0x00]
         );
         );
         check_ok!(
         check_ok!(
             computational_data()
             computational_data()
-                .parse(&[0x0e, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00, 0x67, 0xde, 0x28]),
+                .parse(&[0x0e, 0xf3, 0x35, 0x12, 0x65, 0xff, 0x00, 0x67, 0xde, 0x28], &mut context),
             AmlValue::Integer(0xde6700ff651235f3),
             AmlValue::Integer(0xde6700ff651235f3),
             &[0x28]
             &[0x28]
         );
         );

+ 6 - 6
aml_parser/src/test_utils.rs

@@ -1,21 +1,21 @@
 pub(crate) macro check_err($parse: expr, $error: pat, $remains: expr) {
 pub(crate) macro check_err($parse: expr, $error: pat, $remains: expr) {
     match $parse {
     match $parse {
         Ok(result) => panic!("Expected Err, got {:#?}", result),
         Ok(result) => panic!("Expected Err, got {:#?}", result),
-        Err((remains, $error)) if *remains == *$remains => (),
-        Err((remains, $error)) => {
+        Err((remains, _, $error)) if *remains == *$remains => (),
+        Err((remains, _, $error)) => {
             panic!("Correct error, incorrect stream returned: {:x?}", remains)
             panic!("Correct error, incorrect stream returned: {:x?}", remains)
         }
         }
-        Err((_, err)) => panic!("Got wrong error: {:?}", err),
+        Err((_, _, err)) => panic!("Got wrong error: {:?}", err),
     }
     }
 }
 }
 
 
 pub(crate) macro check_ok($parse: expr, $expected: expr, $remains: expr) {
 pub(crate) macro check_ok($parse: expr, $expected: expr, $remains: expr) {
     match $parse {
     match $parse {
-        Ok((remains, ref result)) if remains == *$remains && result == &$expected => (),
-        Ok((remains, ref result)) if result == &$expected => {
+        Ok((remains, _, ref result)) if remains == *$remains && result == &$expected => (),
+        Ok((remains, _, ref result)) if result == &$expected => {
             panic!("Correct result, incorrect slice returned: {:x?}", remains)
             panic!("Correct result, incorrect slice returned: {:x?}", remains)
         }
         }
         Ok(result) => panic!("Successfully parsed Ok, but it was wrong: {:#?}", result),
         Ok(result) => panic!("Successfully parsed Ok, but it was wrong: {:#?}", result),
-        Err((_, err)) => panic!("Expected Ok, got {:#?}", err),
+        Err((_, _, err)) => panic!("Expected Ok, got {:#?}", err),
     }
     }
 }
 }