use crate::parse::{parse_uleb128_at, ParseAt, ParseErrorContext as _, ParseResult};
use crate::xo65::Xo65Bytes;
#[derive(Debug)]
pub struct ScopeTable<'data> {
bytes: Xo65Bytes<'data>,
scopes: Box<[Scope]>,
}
impl<'data> ScopeTable<'data> {
pub fn as_bytes(&self) -> &'data [u8] {
self.bytes.as_inner()
}
pub fn count(&self) -> usize {
self.scopes.len()
}
pub fn get(&self, idx: usize) -> Option<&Scope> {
self.scopes.get(idx)
}
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = &Scope> + ExactSizeIterator + std::iter::FusedIterator + Clone
{
self.scopes.iter()
}
pub(crate) fn parse(bytes: Xo65Bytes<'data>) -> ParseResult<Self> {
let mut off = 0;
let count = parse_uleb128_at(&bytes, &mut off)? as usize;
let mut scopes = Vec::<Scope>::with_capacity(count);
for i in 0..count {
let scope = Scope::parse_at(&bytes, &mut off)
.with_context(|| format!("scope {i} parse error"))?;
scopes.push(scope);
}
Ok(Self {
bytes,
scopes: scopes.into(),
})
}
}
#[derive(Debug)]
pub struct Scope {
name: u32,
kind: ScopeKind,
parent: u32,
lexical_level: u32,
flags: ScopeFlags,
size: Option<u32>,
label: Option<u32>,
spans: Box<[u32]>,
}
impl Scope {
pub fn name(&self) -> u32 {
self.name
}
pub fn kind(&self) -> ScopeKind {
self.kind
}
pub fn parent(&self) -> u32 {
self.parent
}
pub fn lexical_level(&self) -> u32 {
self.lexical_level
}
pub fn flags(&self) -> ScopeFlags {
self.flags
}
pub fn size(&self) -> Option<u32> {
self.size
}
pub fn label(&self) -> Option<u32> {
self.label
}
pub fn spans(&self) -> &[u32] {
&self.spans
}
}
impl ParseAt<'_> for Scope {
fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
let parent = parse_uleb128_at(bytes, off)?;
let lexical_level = parse_uleb128_at(bytes, off)?;
let flags = parse_uleb128_at(bytes, off).map(ScopeFlags)?;
let kind = parse_uleb128_at(bytes, off).map(ScopeKind::new)?;
let name = parse_uleb128_at(bytes, off)?;
let size = flags
.has_size()
.then(|| parse_uleb128_at(bytes, off))
.transpose()?;
let label = flags
.has_label()
.then(|| parse_uleb128_at(bytes, off))
.transpose()?;
let spans = parse_spans_at(bytes, off)?;
Ok(Self {
name,
kind,
parent,
lexical_level,
flags,
size,
label,
spans,
})
}
}
fn parse_spans_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Box<[u32]>> {
let count = parse_uleb128_at(bytes, off)? as usize;
let mut spans = Vec::<u32>::with_capacity(count);
for _ in 0..count {
let span = parse_uleb128_at(bytes, off)?;
spans.push(span);
}
Ok(spans.into())
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ScopeFlags(u32);
impl ScopeFlags {
pub fn get(self) -> u32 {
self.0
}
pub fn has_size(self) -> bool {
(self.0 & (1 << 0)) != 0
}
pub fn has_label(self) -> bool {
(self.0 & (1 << 1)) != 0
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ScopeKind {
Global = 0,
File = 1,
ScopeProc = 2,
StructUnion = 3,
Enum = 4,
Undefined = 0xFF,
Unknown(u32),
}
impl ScopeKind {
fn new(inner: u32) -> Self {
match inner {
0 => Self::Global,
1 => Self::File,
2 => Self::ScopeProc,
3 => Self::StructUnion,
4 => Self::Enum,
0xFF => Self::Undefined,
_ => Self::Unknown(inner),
}
}
}