Finish up parser and assembler with more-or-less complete syntax
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>
This commit is contained in:
@@ -1,21 +1,38 @@
|
||||
use crate::vm::obj::error::ParseError;
|
||||
use byteorder::{ReadBytesExt, LE};
|
||||
use crate::vm::obj::syn::error::{Result, ParseError};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
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 header: Header,
|
||||
pub sections: Vec<Box<dyn Section>>,
|
||||
pub version: u32,
|
||||
pub sections: Vec<Section>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Header {
|
||||
pub version: u16,
|
||||
pub sections: u16,
|
||||
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 {
|
||||
@@ -25,7 +42,7 @@ macro_rules! section_kind {
|
||||
}
|
||||
) => {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum $enum_name {
|
||||
$($name = $value),*
|
||||
@@ -54,54 +71,79 @@ section_kind! {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Section: Debug {
|
||||
fn header(&self) -> SectionHeader;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SectionHeader {
|
||||
pub kind: SectionKind,
|
||||
pub checksum: u32,
|
||||
pub len: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DataSection {
|
||||
pub header: SectionHeader,
|
||||
pub load_location: u64,
|
||||
pub contents: Vec<u8>,
|
||||
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 for DataSection {
|
||||
fn header(&self) -> SectionHeader {
|
||||
self.header
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CodeSection {
|
||||
pub header: SectionHeader,
|
||||
pub load_location: u64,
|
||||
pub contents: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Section for CodeSection {
|
||||
fn header(&self) -> SectionHeader {
|
||||
self.header
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MetaSection {
|
||||
pub header: SectionHeader,
|
||||
pub entry_count: u64,
|
||||
pub entries: Vec<(String, Vec<u8>)>,
|
||||
}
|
||||
|
||||
impl Section for MetaSection {
|
||||
fn header(&self) -> SectionHeader {
|
||||
self.header
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user