2
0
Эх сурвалжийг харах

Parse ArgObj and LocalObj in TermArg, plus helper methods

Isaac Woods 5 жил өмнө
parent
commit
f9065001b5

+ 29 - 0
aml_parser/src/lib.rs

@@ -60,6 +60,7 @@ pub use crate::{
 
 use alloc::string::String;
 use log::error;
+use misc::{ArgNum, LocalNum};
 use parser::Parser;
 use pkg_length::PkgLength;
 use value::Args;
@@ -106,6 +107,12 @@ pub enum AmlError {
     /*
      * Errors produced executing control methods.
      */
+    /// Produced when a method accesses an argument it does not have (e.g. a method that takes 2
+    /// arguments accesses `Arg4`). The inner value is the number of the argument accessed. If any
+    /// arguments are accessed when a method is not being executed, this error is produced with an
+    /// argument number of `0xff`.
+    InvalidArgumentAccess(ArgNum),
+    InvalidLocalAccess(LocalNum),
     /// This is not a real error, but is used to propagate return values from within the deep
     /// parsing call-stack. It should only be emitted when parsing a `DefReturn`. We use the
     /// error system here because the way errors are propagated matches how we want to handle
@@ -172,4 +179,26 @@ impl AmlContext {
     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())
     }
+
+    pub fn current_arg(&self, arg: ArgNum) -> Result<&AmlValue, AmlError> {
+        self.current_args.as_ref().ok_or(AmlError::InvalidArgumentAccess(0xff))?.arg(arg)
+    }
+
+    /// Get the current value of a local by its local number.
+    ///
+    /// ### Panics
+    /// Panics if an invalid local number is passed (valid local numbers are `0..=7`)
+    pub fn local(&self, local: LocalNum) -> Result<&AmlValue, AmlError> {
+        match local {
+            0 => self.local_0.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            1 => self.local_1.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            2 => self.local_2.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            3 => self.local_3.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            4 => self.local_4.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            5 => self.local_5.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            6 => self.local_6.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            7 => self.local_7.as_ref().ok_or(AmlError::InvalidLocalAccess(local)),
+            _ => panic!("Invalid local number: {}", local),
+        }
+    }
 }

+ 14 - 2
aml_parser/src/term_object.rs

@@ -1,4 +1,5 @@
 use crate::{
+    misc::{arg_obj, local_obj},
     name_object::{name_seg, name_string},
     namespace::AmlName,
     opcode::{self, ext_opcode, opcode},
@@ -518,8 +519,19 @@ where
     /*
      * TermArg := Type2Opcode | DataObject | ArgObj | LocalObj
      */
-    // TODO: this doesn't yet parse ArgObj, or LocalObj
-    comment_scope_verbose("TermArg", choice!(data_object(), make_parser_concrete!(type2_opcode())))
+    comment_scope_verbose(
+        "TermArg",
+        choice!(
+            data_object(),
+            arg_obj().map_with_context(|arg_num, context| {
+                (Ok(try_with_context!(context, context.current_arg(arg_num)).clone()), context)
+            }),
+            local_obj().map_with_context(|local_num, context| {
+                (Ok(try_with_context!(context, context.local(local_num)).clone()), context)
+            }),
+            make_parser_concrete!(type2_opcode())
+        ),
+    )
 }
 
 pub fn data_ref_object<'a, 'c>() -> impl Parser<'a, 'c, AmlValue>

+ 27 - 7
aml_parser/src/value.rs

@@ -1,4 +1,5 @@
 use crate::{
+    misc::ArgNum,
     namespace::AmlName,
     parser::Parser,
     pkg_length::PkgLength,
@@ -202,11 +203,30 @@ impl AmlValue {
 /// A control method can take up to 7 arguments, each of which can be an `AmlValue`.
 #[derive(Clone, Debug, Default)]
 pub struct Args {
-    arg_0: Option<AmlValue>,
-    arg_1: Option<AmlValue>,
-    arg_2: Option<AmlValue>,
-    arg_3: Option<AmlValue>,
-    arg_4: Option<AmlValue>,
-    arg_5: Option<AmlValue>,
-    arg_6: Option<AmlValue>,
+    pub arg_0: Option<AmlValue>,
+    pub arg_1: Option<AmlValue>,
+    pub arg_2: Option<AmlValue>,
+    pub arg_3: Option<AmlValue>,
+    pub arg_4: Option<AmlValue>,
+    pub arg_5: Option<AmlValue>,
+    pub arg_6: Option<AmlValue>,
+}
+
+impl Args {
+    /// Get an argument by its `ArgNum`.
+    ///
+    /// ### Panics
+    /// Panics if passed an invalid argument number (valid argument numbers are `0..=6`)
+    pub fn arg(&self, num: ArgNum) -> Result<&AmlValue, AmlError> {
+        match num {
+            0 => self.arg_0.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            1 => self.arg_1.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            2 => self.arg_2.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            3 => self.arg_3.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            4 => self.arg_4.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            5 => self.arg_5.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            6 => self.arg_6.as_ref().ok_or(AmlError::InvalidArgumentAccess(num)),
+            _ => panic!("Invalid argument number: {}", num),
+        }
+    }
 }