Browse Source

Move method invocation logic into AmlContext

I hoped this would prevent us from having to clone the method, but the
borrow checker still can't work it out :(

I still think this looks cleaner and is more suited to the callstack setup
I think we'll need in the future.
Isaac Woods 5 years ago
parent
commit
3a04c8ab57
2 changed files with 46 additions and 60 deletions
  1. 45 1
      aml_parser/src/lib.rs
  2. 1 59
      aml_parser/src/value.rs

+ 45 - 1
aml_parser/src/lib.rs

@@ -63,6 +63,7 @@ use log::error;
 use misc::{ArgNum, LocalNum};
 use parser::Parser;
 use pkg_length::PkgLength;
+use term_object::term_list;
 use value::Args;
 
 /// AML has a `RevisionOp` operator that returns the "AML interpreter revision". It's not clear
@@ -126,7 +127,50 @@ impl AmlContext {
 
     /// Invoke a method referred to by its path in the namespace, with the given arguments.
     pub fn invoke_method(&mut self, path: &AmlName, args: Args) -> Result<AmlValue, AmlError> {
-        self.namespace.get_by_path(path)?.clone().invoke(self, args, path.clone())
+        if let AmlValue::Method { flags, code } = self.namespace.get_by_path(path)?.clone() {
+            /*
+             * First, set up the state we expect to enter the method with, but clearing local
+             * variables to "null" and setting the arguments.
+             */
+            self.current_scope = path.clone();
+            self.current_args = Some(args);
+            self.local_0 = None;
+            self.local_1 = None;
+            self.local_2 = None;
+            self.local_3 = None;
+            self.local_4 = None;
+            self.local_5 = None;
+            self.local_6 = None;
+            self.local_7 = None;
+
+            let return_value =
+                match term_list(PkgLength::from_raw_length(&code, code.len() as u32)).parse(&code, self) {
+                    // If the method doesn't return a value, we implicitly return `0`
+                    Ok((remaining, context, result)) => Ok(AmlValue::Integer(0)),
+                    Err((remaining, context, AmlError::Return(result))) => Ok(result),
+                    Err((remaining, context, err)) => {
+                        error!("Failed to execute control method: {:?}", err);
+                        Err(err)
+                    }
+                };
+
+            /*
+             * Now clear the state.
+             */
+            self.current_args = None;
+            self.local_0 = None;
+            self.local_1 = None;
+            self.local_2 = None;
+            self.local_3 = None;
+            self.local_4 = None;
+            self.local_5 = None;
+            self.local_6 = None;
+            self.local_7 = None;
+
+            return_value
+        } else {
+            Err(AmlError::IncompatibleValueConversion)
+        }
     }
 
     pub(crate) fn current_arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {

+ 1 - 59
aml_parser/src/value.rs

@@ -1,15 +1,6 @@
-use crate::{
-    misc::ArgNum,
-    namespace::AmlName,
-    parser::Parser,
-    pkg_length::PkgLength,
-    term_object::term_list,
-    AmlContext,
-    AmlError,
-};
+use crate::{misc::ArgNum, namespace::AmlName, AmlError};
 use alloc::{boxed::Box, string::String, vec::Vec};
 use bit_field::BitField;
-use log::{error, info};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum RegionSpace {
@@ -218,55 +209,6 @@ impl AmlValue {
             _ => Err(AmlError::IncompatibleValueConversion),
         }
     }
-
-    /// If this value is a control method, invoke it. Returns `AmlError::IncompatibleValueConversion` if this
-    /// is not a method.
-    pub fn invoke(&self, context: &mut AmlContext, args: Args, scope: AmlName) -> Result<AmlValue, AmlError> {
-        if let AmlValue::Method { flags, ref code } = self {
-            /*
-             * First, set up the state we expect to enter the method with, but clearing local
-             * variables to "null" and setting the arguments.
-             */
-            context.current_scope = scope;
-            context.current_args = Some(args);
-            context.local_0 = None;
-            context.local_1 = None;
-            context.local_2 = None;
-            context.local_3 = None;
-            context.local_4 = None;
-            context.local_5 = None;
-            context.local_6 = None;
-            context.local_7 = None;
-
-            let return_value =
-                match term_list(PkgLength::from_raw_length(code, code.len() as u32)).parse(code, context) {
-                    // If the method doesn't return a value, we implicitly return `0`
-                    Ok((remaining, context, result)) => Ok(AmlValue::Integer(0)),
-                    Err((remaining, context, AmlError::Return(result))) => Ok(result),
-                    Err((remaining, context, err)) => {
-                        error!("Failed to execute control method: {:?}", err);
-                        Err(err)
-                    }
-                };
-
-            /*
-             * Now clear the state.
-             */
-            context.current_args = None;
-            context.local_0 = None;
-            context.local_1 = None;
-            context.local_2 = None;
-            context.local_3 = None;
-            context.local_4 = None;
-            context.local_5 = None;
-            context.local_6 = None;
-            context.local_7 = None;
-
-            return_value
-        } else {
-            Err(AmlError::IncompatibleValueConversion)
-        }
-    }
 }
 
 /// A control method can take up to 7 arguments, each of which can be an `AmlValue`.