Major changes inlude: * Bit the bullet and now instructions have their length hard-coded * Move from_utf8 object parsing to be done by their objects (instead of a Parser god object) * A list of AST sections are assembled into an Object using the new vm::obj::assemble module. * Changed the object layout some in the spec, and adjusted code to match this. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
150 lines
4.0 KiB
Rust
150 lines
4.0 KiB
Rust
use byteorder::{ReadBytesExt, LE};
|
|
use crate::vm::obj::syn::error::{Result, ParseError};
|
|
use std::{
|
|
collections::HashMap,
|
|
convert::{TryFrom, TryInto},
|
|
fmt::Debug,
|
|
io::{Cursor, Read},
|
|
};
|
|
|
|
pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11;
|
|
const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4
|
|
|
|
#[derive(Debug)]
|
|
pub struct Object {
|
|
pub version: u32,
|
|
pub sections: Vec<Section>,
|
|
}
|
|
|
|
impl Object {
|
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
|
|
let mut cursor = Cursor::new(bytes);
|
|
let magic = cursor.read_u64::<LE>()?;
|
|
if magic != magic {
|
|
return Err(ParseError::WrongMagic);
|
|
}
|
|
let version = cursor.read_u32::<LE>()?;
|
|
let section_count = cursor.read_u32::<LE>()?;
|
|
|
|
let mut sections = Vec::new();
|
|
for _ in 0 .. section_count {
|
|
let section = Section::from_bytes(&mut cursor)?;
|
|
sections.push(section);
|
|
}
|
|
Ok(Object { version, sections })
|
|
}
|
|
}
|
|
|
|
macro_rules! section_kind {
|
|
(
|
|
pub enum $enum_name:ident {
|
|
$($name:ident = $value:expr),* $(,)?
|
|
}
|
|
) => {
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[repr(u8)]
|
|
pub enum $enum_name {
|
|
$($name = $value),*
|
|
}
|
|
|
|
impl TryFrom<u8> for SectionKind {
|
|
type Error = ParseError;
|
|
|
|
fn try_from(other: u8) -> std::result::Result<Self, Self::Error> {
|
|
match other {
|
|
$(
|
|
$value => Ok($enum_name::$name),
|
|
)*
|
|
_ => Err(ParseError::UnknownSectionKind { kind: other }),
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
section_kind! {
|
|
pub enum SectionKind {
|
|
Data = 0x00,
|
|
Code = 0x10,
|
|
Meta = 0xFF,
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Section {
|
|
Data {
|
|
start: u64,
|
|
end: u64,
|
|
contents: Vec<u8>,
|
|
},
|
|
Code {
|
|
start: u64,
|
|
end: u64,
|
|
contents: Vec<u8>,
|
|
},
|
|
Meta {
|
|
entries: HashMap<String, u64>,
|
|
},
|
|
}
|
|
|
|
impl Section {
|
|
fn from_bytes(cursor: &mut Cursor<&[u8]>) -> Result<Self> {
|
|
let len = cursor.read_u64::<LE>()?;
|
|
let start = cursor.position() as usize;
|
|
let end = start + len as usize;
|
|
|
|
let bytes = &cursor.get_ref()[start .. end];
|
|
let kind: SectionKind = cursor.read_u8()?.try_into()?;
|
|
match kind {
|
|
SectionKind::Data => Section::data_section_from_bytes(bytes),
|
|
SectionKind::Code => Section::code_section_from_bytes(bytes),
|
|
SectionKind::Meta => Section::meta_section_from_bytes(bytes),
|
|
}
|
|
}
|
|
|
|
fn data_section_from_bytes(bytes: &[u8]) -> Result<Self> {
|
|
let mut cursor = Cursor::new(bytes);
|
|
let start = cursor.read_u64::<LE>()?;
|
|
let end = cursor.read_u64::<LE>()?;
|
|
let contents = &bytes[cursor.position() as usize..];
|
|
Ok(Section::Data {
|
|
start,
|
|
end,
|
|
contents: From::from(contents),
|
|
})
|
|
}
|
|
|
|
fn code_section_from_bytes(bytes: &[u8]) -> Result<Self> {
|
|
let mut cursor = Cursor::new(bytes);
|
|
let start = cursor.read_u64::<LE>()?;
|
|
let end = cursor.read_u64::<LE>()?;
|
|
let contents = &bytes[cursor.position() as usize..];
|
|
Ok(Section::Code {
|
|
start,
|
|
end,
|
|
contents: From::from(contents),
|
|
})
|
|
}
|
|
|
|
fn meta_section_from_bytes(bytes: &[u8]) -> Result<Self> {
|
|
let mut cursor = Cursor::new(bytes);
|
|
let entry_count = cursor.read_u64::<LE>()?;
|
|
let mut entries = HashMap::new();
|
|
for _ in 0 .. entry_count {
|
|
// key
|
|
let key_len = cursor.read_u64::<LE>()?;
|
|
let mut key_bytes = vec![0u8; key_len as usize];
|
|
cursor.read_exact(&mut key_bytes)?;
|
|
let key = String::from_utf8(key_bytes)?;
|
|
|
|
// value
|
|
let value = cursor.read_u64::<LE>()?;
|
|
entries.insert(key, value);
|
|
}
|
|
Ok(Section::Meta {
|
|
entries
|
|
})
|
|
}
|
|
}
|