Bläddra i källkod

Parse the start of MethodInvocation (hopefully)

This is a super unclear part of the spec, so I'm not sure whether this is
even correct (but it does appear to work as intended with the QEMU tables).
It seems incorrect to treat non-method objects as invocable by a
MethodInvocation, but I can't think what else must parse these objects.
Isaac Woods 5 år sedan
förälder
incheckning
75e6c9075e
1 ändrade filer med 60 tillägg och 3 borttagningar
  1. 60 3
      aml_parser/src/type2.rs

+ 60 - 3
aml_parser/src/type2.rs

@@ -1,7 +1,12 @@
 use crate::{
-    parser::{choice, comment_scope_verbose, Parser},
+    name_object::name_string,
+    opcode::{self, opcode},
+    parser::{choice, comment_scope_verbose, ParseResult, Parser},
+    term_object::term_arg,
     value::AmlValue,
+    AmlError,
 };
+use alloc::boxed::Box;
 
 /// Type 2 opcodes return a value and so can be used in expressions.
 pub fn type2_opcode<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
@@ -19,6 +24,58 @@ where
      *                DefSubtract | DefTimer | DefToBCD | DefToBuffer | DefToDecimalString |
      *                DefToHexString | DefToInteger | DefToString | DefWait | DefXOr | MethodInvocation
      */
-    // TODO
-    comment_scope_verbose("Type2Opcode", choice!())
+    comment_scope_verbose("Type2Opcode", choice!(method_invocation()))
+}
+
+fn method_invocation<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>
+where
+    'c: 'a,
+{
+    /*
+     * MethodInvocation := NameString TermArgList
+     *
+     * MethodInvocation is the worst of the AML structures, because you're meant to figure out how
+     * much you're meant to parse using the name of the method (by knowing from its definition how
+     * how many arguments it takes). However, the definition of a method can in theory appear after
+     * an invocation of that method, and so parsing them properly can be very difficult.
+     * NOTE: We don't support the case of the definition appearing after the invocation.
+     *
+     * It's also not clear whether things that aren't methods can be "invoked" using
+     * MethodInvocation with 0 arguments. It seems that references to DefNames can be encoded using
+     * MethodInvocation, at least, and should just be looked up.
+     */
+    comment_scope_verbose(
+        "MethodInvocation",
+        name_string()
+            .map_with_context(move |name, context| {
+                let object = match context.lookup(&name) {
+                    Some(object) => (*object).clone(),
+                    None => return (Err(AmlError::ObjectDoesNotExist(name.as_string())), context),
+                };
+
+                (Ok(object), context)
+            })
+            .feed(|object| {
+                move |input: &'a [u8], context| -> ParseResult<'a, 'c, AmlValue> {
+                    match object.clone() {
+                        AmlValue::Name(boxed_value) => Ok((input, context, unbox(boxed_value))),
+
+                        AmlValue::Method { flags, ref code } => {
+                            // TODO: before we do this, we need to restructure the structures to allow us
+                            // to execute control methods from inside other control methods
+                            // TODO
+                            unimplemented!()
+                        }
+
+                        _ => Err((input, context, AmlError::IncompatibleValueConversion)),
+                    }
+                }
+            }),
+    )
+}
+
+/// An unfortunate helper method to unbox an owned, boxed value. `*x` is special-cased for `Box`
+/// here, but the compiler needs the type signature of the method to figure it out.
+fn unbox<T>(x: Box<T>) -> T {
+    *x
 }