Files
rasp/src/vm/obj/obj.rs
Alek Ratzloff e198da5825 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>
2020-02-09 13:04:56 -05:00

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