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:
2020-02-09 13:04:56 -05:00
parent 329e61e087
commit e198da5825
19 changed files with 739 additions and 311 deletions

View File

@@ -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
}
}