use crate::vm::inst::Inst; use byteorder::{ReadBytesExt, LE}; use snafu::{ensure, Snafu}; use std::{ convert::{TryFrom, TryInto}, fmt::Debug, io::{self, Cursor, Read}, }; pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11; #[derive(Debug)] pub struct Object { header: Header, sections: Vec>, } #[derive(Debug, Clone, Copy)] pub struct Header { version: u16, sections: u16, } macro_rules! section_kind { ( pub enum $enum_name:ident { $($name:ident = $value:expr),* $(,)? } ) => { #[derive(Debug, Clone, Copy)] #[repr(u8)] pub enum $enum_name { $($name = $value),* } impl TryFrom for SectionKind { type Error = ParseError; fn try_from(other: u8) -> std::result::Result { match other { $( $value => Ok($enum_name::$name), )* _ => Err(ParseError::UnknownSectionKind { kind: other }), } } } }; } section_kind! { pub enum SectionKind { Data = 0x00, Code = 0x10, Meta = 0xFF, } } pub trait Section: Debug { fn header(&self) -> SectionHeader; } #[derive(Debug, Clone, Copy)] pub struct SectionHeader { kind: SectionKind, checksum: u32, len: u64, } #[derive(Debug, Clone)] pub struct DataSection { header: SectionHeader, load_location: u64, contents: Vec, } impl Section for DataSection { fn header(&self) -> SectionHeader { self.header } } #[derive(Debug, Clone)] pub struct CodeSection { header: SectionHeader, load_location: u64, contents: Vec, } impl Section for CodeSection { fn header(&self) -> SectionHeader { self.header } } #[derive(Debug, Clone)] pub struct MetaSection { header: SectionHeader, entry_count: u64, entries: Vec<(String, Vec)>, } impl Section for MetaSection { fn header(&self) -> SectionHeader { self.header } } #[derive(Debug, Clone)] pub struct ObjectParser { bytes: Cursor>, } impl ObjectParser { pub fn parse(&mut self) -> Result { let header = self.parse_header()?; let sections = self.parse_sections()?; Ok(Object { header, sections }) } fn parse_header(&mut self) -> Result
{ let magic = self.bytes.read_u64::()?; ensure!(magic == MAGIC, WrongMagic); let version = self.bytes.read_u16::()?; let sections = self.bytes.read_u16::()?; Ok(Header { version, sections }) } fn parse_sections(&mut self) -> Result>> { todo!() } fn parse_section(&mut self) -> Result> { let header = self.parse_section_header()?; let section: Box = match header.kind { SectionKind::Data => self.parse_data_section(header).map(Box::new)?, SectionKind::Code => self.parse_code_section(header).map(Box::new)?, SectionKind::Meta => self.parse_meta_section(header).map(Box::new)?, }; Ok(section) } fn parse_section_header(&mut self) -> Result { let kind: SectionKind = self.bytes.read_u8()?.try_into()?; let checksum = self.bytes.read_u32::()?; let len = self.bytes.read_u64::()?; Ok(SectionHeader { kind, checksum, len, }) } fn parse_data_section(&mut self, header: SectionHeader) -> Result { let load_location = self.bytes.read_u64::()?; let contents = self.take_bytes(header.len)?; Ok(DataSection { header, load_location, contents, }) } fn parse_code_section(&mut self, _header: SectionHeader) -> Result { let _load_location = self.bytes.read_u64::()?; todo!("instruction parsing") } fn parse_meta_section(&mut self, header: SectionHeader) -> Result { let entry_count = self.bytes.read_u64::()?; let mut entries = Vec::with_capacity(entry_count as usize); for offset in 0 .. entry_count { let key_bytes = self.parse_sized_data()?; let key = String::from_utf8(key_bytes)?; let value = self.parse_sized_data()?; entries.push((key, value)); } Ok(MetaSection { header, entry_count, entries, }) } fn parse_sized_data(&mut self) -> Result> { let size = self.bytes.read_u64::()?; self.take_bytes(size) } fn take_bytes(&mut self, count: u64) -> Result> { let mut contents = vec!(0u8; count as usize); self.bytes.read_exact(&mut contents)?; Ok(contents) } } #[derive(Debug, Snafu)] pub enum ParseError { #[snafu(display("IO error: {}", source))] Io { source: io::Error }, #[snafu(display("wrong magic number"))] WrongMagic, #[snafu(display("unknown section kind: 0x{:02x}", kind))] UnknownSectionKind { kind: u8 }, #[snafu(display("invalid UTF-8 string: {}", source))] InvalidUtf8String { source: std::string::FromUtf8Error }, } macro_rules! into_parse_error { ( $($type:ty : $variant:ident),* $(,)? ) => { $( impl From<$type> for ParseError { fn from(other: $type) -> Self { ParseError::$variant { source: other } } } )* } } into_parse_error! { io::Error: Io, std::string::FromUtf8Error: InvalidUtf8String, } pub type Result = std::result::Result;