use crate::{
misc::{arg_obj, debug_obj, local_obj, ArgNum, LocalNum},
namespace::{AmlName, NameComponent},
opcode::{opcode, DUAL_NAME_PREFIX, MULTI_NAME_PREFIX, NULL_NAME, PREFIX_CHAR, ROOT_CHAR},
parser::{choice, comment_scope, consume, n_of, take, take_while, Parser, Propagate},
AmlContext,
AmlError,
DebugVerbosity,
};
use alloc::vec::Vec;
use core::{fmt, str};
#[derive(Clone, Debug)]
pub enum Target {
Null,
Name(AmlName),
Debug,
Arg(ArgNum),
Local(LocalNum),
}
pub fn target<'a, 'c>() -> impl Parser<'a, 'c, Target>
where
'c: 'a,
{
comment_scope(
DebugVerbosity::AllScopes,
"Target",
choice!(null_name().map(|_| Ok(Target::Null)), super_name()),
)
}
pub fn super_name<'a, 'c>() -> impl Parser<'a, 'c, Target>
where
'c: 'a,
{
comment_scope(
DebugVerbosity::AllScopes,
"SuperName",
choice!(debug_obj().map(|()| Ok(Target::Debug)), simple_name()),
)
}
pub fn simple_name<'a, 'c>() -> impl Parser<'a, 'c, Target>
where
'c: 'a,
{
comment_scope(
DebugVerbosity::AllScopes,
"SimpleName",
choice!(
arg_obj().map(|arg_num| Ok(Target::Arg(arg_num))),
local_obj().map(|local_num| Ok(Target::Local(local_num))),
name_string().map(move |name| Ok(Target::Name(name)))
),
)
}
pub fn name_string<'a, 'c>() -> impl Parser<'a, 'c, AmlName>
where
'c: 'a,
{
let root_name_string = opcode(ROOT_CHAR).then(name_path()).map(|((), ref name_path)| {
let mut name = alloc::vec![NameComponent::Root];
name.extend_from_slice(name_path);
Ok(AmlName::from_components(name))
});
let prefix_path =
take_while(opcode(PREFIX_CHAR)).then(name_path()).map(|(num_prefix_chars, ref name_path)| {
let mut name = alloc::vec![NameComponent::Prefix; num_prefix_chars];
name.extend_from_slice(name_path);
Ok(AmlName::from_components(name))
});
comment_scope(DebugVerbosity::AllScopes, "NameString", move |input: &'a [u8], context| {
let first_char = match input.first() {
Some(&c) => c,
None => return Err((input, context, Propagate::Err(AmlError::UnexpectedEndOfStream))),
};
match first_char {
ROOT_CHAR => root_name_string.parse(input, context),
PREFIX_CHAR => prefix_path.parse(input, context),
_ => name_path()
.map(|path| {
if path.len() == 0 {
return Err(Propagate::Err(AmlError::EmptyNamesAreInvalid));
}
Ok(AmlName::from_components(path))
})
.parse(input, context),
}
})
}
pub fn name_path<'a, 'c>() -> impl Parser<'a, 'c, Vec<NameComponent>>
where
'c: 'a,
{
choice!(
null_name(),
dual_name_path(),
multi_name_path(),
name_seg().map(|seg| Ok(alloc::vec![NameComponent::Segment(seg)]))
)
}
pub fn null_name<'a, 'c>() -> impl Parser<'a, 'c, Vec<NameComponent>>
where
'c: 'a,
{
opcode(NULL_NAME).map(|_| Ok(Vec::with_capacity(0)))
}
pub fn dual_name_path<'a, 'c>() -> impl Parser<'a, 'c, Vec<NameComponent>>
where
'c: 'a,
{
opcode(DUAL_NAME_PREFIX).then(name_seg()).then(name_seg()).map(|(((), first), second)| {
Ok(alloc::vec![NameComponent::Segment(first), NameComponent::Segment(second)])
})
}
pub fn multi_name_path<'a, 'c>() -> impl Parser<'a, 'c, Vec<NameComponent>>
where
'c: 'a,
{
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, context, name_segs.iter().map(|&seg| NameComponent::Segment(seg)).collect()))
}
Err((_, context, err)) => Err((input, context, err)),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct NameSeg(pub(crate) [u8; 4]);
impl NameSeg {
pub(crate) fn from_str(string: &str) -> Result<NameSeg, AmlError> {
if string.len() < 1 || string.len() > 4 {
return Err(AmlError::InvalidNameSeg);
}
let mut seg = [b'_'; 4];
let bytes = string.as_bytes();
if !is_lead_name_char(bytes[0]) {
return Err(AmlError::InvalidNameSeg);
}
seg[0] = bytes[0];
for i in 1..bytes.len() {
if !is_name_char(bytes[i]) {
return Err(AmlError::InvalidNameSeg);
}
seg[i] = bytes[i];
}
Ok(NameSeg(seg))
}
pub fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.0) }
}
}
impl fmt::Debug for NameSeg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.as_str())
}
}
pub fn name_seg<'a, 'c>() -> impl Parser<'a, 'c, NameSeg>
where
'c: 'a,
{
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])))
}
}
fn is_lead_name_char(byte: u8) -> bool {
(byte >= b'A' && byte <= b'Z') || byte == b'_'
}
fn is_digit_char(byte: u8) -> bool {
byte >= b'0' && byte <= b'9'
}
fn is_name_char(byte: u8) -> bool {
is_lead_name_char(byte) || is_digit_char(byte)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{parser::Parser, test_utils::*, AmlError};
#[test]
fn test_name_seg() {
let mut context = crate::test_utils::make_test_context();
check_ok!(
name_seg().parse(&[b'A', b'F', b'3', b'Z'], &mut context),
NameSeg([b'A', b'F', b'3', b'Z']),
&[]
);
check_ok!(
name_seg().parse(&[b'A', b'F', b'3', b'Z', 0xff], &mut context),
NameSeg([b'A', b'F', b'3', b'Z']),
&[0xff]
);
check_err!(
name_seg().parse(&[0xff, b'E', b'A', b'7'], &mut context),
AmlError::UnexpectedByte(0xff),
&[0xff, b'E', b'A', b'7']
);
check_err!(name_seg().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
}
#[test]
fn test_name_path() {
let mut context = crate::test_utils::make_test_context();
check_err!(name_path().parse(&[], &mut context), AmlError::UnexpectedEndOfStream, &[]);
check_ok!(name_path().parse(&[0x00], &mut context), alloc::vec![], &[]);
check_ok!(name_path().parse(&[0x00, 0x00], &mut context), alloc::vec![], &[0x00]);
check_err!(name_path().parse(&[0x2e, b'A'], &mut context), AmlError::UnexpectedEndOfStream, &[0x2e, b'A']);
check_ok!(
name_path().parse(&[0x2e, b'A', b'B', b'C', b'D', b'E', b'_', b'F', b'G'], &mut context),
alloc::vec![
NameComponent::Segment(NameSeg([b'A', b'B', b'C', b'D'])),
NameComponent::Segment(NameSeg([b'E', b'_', b'F', b'G']))
],
&[]
);
}
#[test]
fn test_prefix_path() {
let mut context = crate::test_utils::make_test_context();
check_ok!(
name_string().parse(&[b'^', b'A', b'B', b'C', b'D'], &mut context),
AmlName::from_str("^ABCD").unwrap(),
&[]
);
check_ok!(
name_string().parse(&[b'^', b'^', b'^', b'A', b'B', b'C', b'D'], &mut context),
AmlName::from_str("^^^ABCD").unwrap(),
&[]
);
}
}