Browse Source

Provide method to lookup the value at a given path

Isaac Woods 5 years ago
parent
commit
82acbf120a
2 changed files with 62 additions and 4 deletions
  1. 15 4
      aml_parser/src/lib.rs
  2. 47 0
      aml_parser/src/name_object.rs

+ 15 - 4
aml_parser/src/lib.rs

@@ -11,6 +11,11 @@
 //! unmap the memory the table was mapped into - all the information needed will be extracted and
 //! allocated on the heap.
 //!
+//! You can then access specific objects by name like so: e.g.
+//! ```
+//! let my_aml_value = aml_context.lookup(&AmlName::from_str("\\_SB.PCI0.S08._ADR").unwrap());
+//! ```
+//!
 //! ### About the parser
 //! The parser is written using a set of custom parser combinators - the code can be confusing on
 //! first reading, but provides an extensible and type-safe way to write parsers. For an easy
@@ -44,11 +49,10 @@ pub(crate) mod pkg_length;
 pub(crate) mod term_object;
 pub mod value;
 
-pub use crate::value::AmlValue;
+pub use crate::{name_object::AmlName, value::AmlValue};
 
 use alloc::collections::BTreeMap;
 use log::error;
-use name_object::AmlName;
 use parser::Parser;
 use pkg_length::PkgLength;
 
@@ -73,7 +77,7 @@ pub enum AmlError {
 
 #[derive(Debug)]
 pub struct AmlContext {
-    namespace: BTreeMap<AmlName, AmlValue>,
+    pub namespace: BTreeMap<AmlName, AmlValue>,
     current_scope: AmlName,
 }
 
@@ -99,7 +103,7 @@ impl AmlContext {
 
     /// Resolves a given path relative to the current scope (if the given path is not absolute).
     /// The returned path can be used to index the namespace.
-    pub fn resolve_path(&mut self, path: &AmlName) -> AmlName {
+    pub fn resolve_path(&self, path: &AmlName) -> AmlName {
         // TODO: we should normalize the path by resolving prefix chars etc.
 
         // If the path is absolute, just return it.
@@ -113,6 +117,13 @@ impl AmlContext {
         new_path
     }
 
+    /// Lookup the object at the given path of the namespace. If the given path is not absolute, it
+    /// is resolved against the current scope. Returns `None` if no object exists at that path.
+    pub fn lookup(&self, path: &AmlName) -> Option<&AmlValue> {
+        let resolved_path = self.resolve_path(&path);
+        self.namespace.get(&resolved_path)
+    }
+
     /// Add an `AmlValue` to the namespace. `path` can either be absolute, or relative (in which
     /// case it's treated as relative to the current scope).
     pub fn add_to_namespace(&mut self, path: AmlName, value: AmlValue) {

+ 47 - 0
aml_parser/src/name_object.rs

@@ -22,6 +22,26 @@ impl AmlName {
         AmlName(alloc::vec![NameComponent::Segment(seg)])
     }
 
+    /// Convert a string representation of an AML name into an `AmlName`. Returns `None` if the
+    /// passed string is not a valid AML path.
+    pub fn from_str(mut string: &str) -> Option<AmlName> {
+        let mut components = Vec::new();
+
+        // If it starts with a \, make it an absolute name
+        if string.starts_with('\\') {
+            components.push(NameComponent::Root);
+            string = &string[1..];
+        }
+
+        // Divide the rest of it into segments, and parse those
+        for part in string.split('.') {
+            // TODO: handle prefix chars
+            components.push(NameComponent::Segment(NameSeg::from_str(part)?));
+        }
+
+        Some(AmlName(components))
+    }
+
     pub fn as_string(&self) -> String {
         self.0
             .iter()
@@ -147,6 +167,33 @@ where
 pub struct NameSeg([u8; 4]);
 
 impl NameSeg {
+    pub(crate) fn from_str(string: &str) -> Option<NameSeg> {
+        // Each NameSeg can only have four chars, and must have at least one
+        if string.len() < 1 || string.len() > 4 {
+            return None;
+        }
+
+        // We pre-fill the array with '_', so it will already be correct if the length is < 4
+        let mut seg = [b'_'; 4];
+        let bytes = string.as_bytes();
+
+        // Manually do the first one, because we have to check it's a LeadNameChar
+        if !is_lead_name_char(bytes[0]) {
+            return None;
+        }
+        seg[0] = bytes[0];
+
+        // Copy the rest of the chars, checking that they're NameChars
+        for i in 1..bytes.len() {
+            if !is_name_char(bytes[i]) {
+                return None;
+            }
+            seg[i] = bytes[i];
+        }
+
+        Some(NameSeg(seg))
+    }
+
     /// Turn a `NameSeg` into a `&str`. Returns it in a `ParseResult` so it's easy to use from
     /// inside parsers.
     pub fn as_str(&self) -> &str {