use crate::parse::{parse_uleb128_at, ParseAt, ParseErrorContext as _, ParseResult};
use crate::xo65::Xo65Bytes;
#[derive(Debug)]
pub struct LineInfoTable<'data> {
bytes: Xo65Bytes<'data>,
infos: Box<[LineInfo]>,
}
impl<'data> LineInfoTable<'data> {
pub fn as_bytes(&self) -> &'data [u8] {
self.bytes.as_inner()
}
pub fn count(&self) -> usize {
self.infos.len()
}
pub fn get(&self, idx: usize) -> Option<&LineInfo> {
self.infos.get(idx)
}
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = &LineInfo> + ExactSizeIterator + std::iter::FusedIterator + Clone
{
self.infos.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 infos = Vec::<LineInfo>::with_capacity(count);
for i in 0..count {
let info = LineInfo::parse_at(&bytes, &mut off)
.with_context(|| format!("line info {i} parse error"))?;
infos.push(info);
}
Ok(Self {
bytes,
infos: infos.into(),
})
}
}
#[derive(Debug)]
pub struct LineInfo {
file: u32,
row: u32,
col: u32,
count: u32,
kind: LineInfoKind,
spans: Box<[u32]>,
}
impl LineInfo {
pub fn file(&self) -> u32 {
self.file
}
pub fn row(&self) -> u32 {
self.row
}
pub fn col(&self) -> u32 {
self.col
}
pub fn count(&self) -> u32 {
self.count
}
pub fn kind(&self) -> LineInfoKind {
self.kind
}
pub fn spans(&self) -> &[u32] {
&self.spans
}
}
impl ParseAt<'_> for LineInfo {
fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
let row = parse_uleb128_at(bytes, off)?;
let col = parse_uleb128_at(bytes, off)?;
let file = parse_uleb128_at(bytes, off)?;
let (kind, count) = {
let value = parse_uleb128_at(bytes, off)?;
(LineInfoKind::new(value & 3), value >> 2)
};
let spans = parse_spans_at(bytes, off)?;
Ok(Self {
file,
row,
col,
count,
kind,
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())
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
Asm = 0,
Extern = 1,
Macro = 2,
MacroParam = 3,
}
impl LineInfoKind {
fn new(inner: u32) -> Self {
match inner {
0 => Self::Asm,
1 => Self::Extern,
2 => Self::Macro,
3 => Self::MacroParam,
_ => unreachable!(),
}
}
}