use crate::expr::Expr;
use crate::parse::{parse_uleb128_at, ParseAt, ParseErrorContext as _, ParseResult};
use crate::xo65::Xo65Bytes;
#[derive(Debug)]
pub struct AssertTable<'data> {
bytes: Xo65Bytes<'data>,
asserts: Box<[Assert]>,
}
impl<'data> AssertTable<'data> {
pub fn as_bytes(&self) -> &'data [u8] {
self.bytes.as_inner()
}
pub fn count(&self) -> usize {
self.asserts.len()
}
pub fn get(&self, idx: usize) -> Option<&Assert> {
self.asserts.get(idx)
}
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = &Assert> + ExactSizeIterator + std::iter::FusedIterator + Clone
{
self.asserts.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 asserts = Vec::<Assert>::with_capacity(count);
for i in 0..count {
let assert = Assert::parse_at(&bytes, &mut off)
.with_context(|| format!("assert {i} parse error"))?;
asserts.push(assert);
}
Ok(Self {
bytes,
asserts: asserts.into(),
})
}
}
#[derive(Debug)]
pub struct Assert {
expr: Expr,
action: AssertAction,
message: u32,
lines: Box<[u32]>,
}
impl Assert {
pub fn expr(&self) -> &Expr {
&self.expr
}
pub fn action(&self) -> AssertAction {
self.action
}
pub fn message(&self) -> u32 {
self.message
}
pub fn lines(&self) -> &[u32] {
&self.lines
}
}
impl ParseAt<'_> for Assert {
fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
let expr = Expr::parse_at(bytes, off)?;
let action = parse_uleb128_at(bytes, off).map(AssertAction::new)?;
let message = parse_uleb128_at(bytes, off)?;
let lines = parse_lines_at(bytes, off)?;
Ok(Self {
expr,
action,
message,
lines,
})
}
}
fn parse_lines_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Box<[u32]>> {
let count = parse_uleb128_at(bytes, off)? as usize;
let mut lines = Vec::<u32>::with_capacity(count);
for _ in 0..count {
let line = parse_uleb128_at(bytes, off)?;
lines.push(line);
}
Ok(lines.into())
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AssertAction {
AsmWarn = 0x00,
AsmError = 0x01,
LinkWarn = 0x02,
LinkError = 0x03,
Unknown(u32),
}
impl AssertAction {
fn new(inner: u32) -> Self {
match inner {
0x00 => Self::AsmWarn,
0x01 => Self::AsmError,
0x02 => Self::LinkWarn,
0x03 => Self::LinkError,
_ => Self::Unknown(inner),
}
}
}