use vermilion_vm::{VirtualMachine, VermilionSection, VermilionSymbol};
use std::collections::HashMap;
#[derive(Clone)]
pub enum Symbol {
External(String),
Local(String, usize),
}
#[derive(Clone)]
pub struct Artifact {
pub data: Vec<u8>,
pub program: Vec<u8>,
pub symbols: HashMap<i64, Symbol>,
}
impl Artifact {
pub fn new() -> Self {
Artifact {
data: vec![],
program: vec![],
symbols: HashMap::new(),
}
}
pub fn define_function(&mut self, id: i64, name: String, bytes: Vec<u8>) {
let start = self.program.len();
self.symbols.insert(id, Symbol::Local(name, start));
self.program.append(&mut bytes.clone());
}
pub fn declare_function(&mut self, id: i64, name: String) {
self.symbols.insert(id, Symbol::External(name));
}
pub fn new_vm(&mut self) -> VirtualMachine {
let mut vm = VirtualMachine::new();
self.load_vm(&mut vm);
vm
}
pub fn load_vm(&mut self, vm: &mut VirtualMachine) {
let mut program = self.program.clone();
let mut data = self.data.clone();
vm.heap.append(&mut program);
vm.heap.append(&mut data);
vm.sections.insert(0 as i64, VermilionSection(0, program.len()));
vm.sections.insert(1 as i64, VermilionSection(program.len(), program.len() + data.len()));
for symbol in self.symbols.clone() {
match symbol.1 {
Symbol::Local(name, home) => {
vm.symbols.insert(symbol.0, VermilionSymbol::Internal(name, home as i64));
},
Symbol::External(name) => {
vm.symbols.insert(symbol.0, VermilionSymbol::UndefinedExternal(name));
}
}
}
}
pub fn from_bytes(bytes: Vec<u8>) -> Result<Artifact, String> {
if bytes.len() < 5 {
return Err("Invalid magic word.".to_string());
}
if bytes.len() < 14 {
return Err("Invalid symbol count.".to_string());
}
let s = bytes[0..4].to_vec();
let expected = vec![
'_' as u8,
'_' as u8,
'v' as u8,
'r' as u8,
'm' as u8,
];
if s != expected {
return Err("Invalid magic word.".to_string());
}
let st_length_bytes = &bytes[5..13];
let st_length = i64::from_le_bytes([
st_length_bytes[0],
st_length_bytes[1],
st_length_bytes[2],
st_length_bytes[3],
st_length_bytes[4],
st_length_bytes[5],
st_length_bytes[6],
st_length_bytes[7],
]);
let mut start_byte = 14;
let mut i = 0;
let mut artifact = Artifact::new();
while i < st_length {
if bytes.len() < st_length as usize + 8 {
return Err("Invalid symbol id.".to_string());
}
let id_bytes = &bytes[start_byte..start_byte + 7];
let id = i64::from_le_bytes([
id_bytes[0],
id_bytes[1],
id_bytes[2],
id_bytes[3],
id_bytes[4],
id_bytes[5],
id_bytes[6],
id_bytes[7],
]);
start_byte += 8;
if bytes.len() < st_length as usize + 8 {
return Err("Invalid symbol address.".to_string());
}
let home_bytes = &bytes[start_byte..start_byte + 7];
let home = i64::from_le_bytes([
home_bytes[0],
home_bytes[1],
home_bytes[2],
home_bytes[3],
home_bytes[4],
home_bytes[5],
home_bytes[6],
home_bytes[7],
]);
start_byte += 8;
if bytes.len() < st_length as usize + 1 {
return Err("Invalid symbol address.".to_string());
}
let type_byte = bytes[start_byte];
start_byte += 1;
let mut name_bytes = Vec::new();
let mut ended = false;
while start_byte < bytes.len() {
if bytes[start_byte] == 0 {
ended = true;
break;
}
name_bytes.push(bytes[start_byte]);
start_byte += 1;
}
if !ended {
return Err("Unterminated string.".to_string());
}
match std::str::from_utf8(&name_bytes) {
Ok(name) => {
if type_byte == 0 {
artifact.symbols.insert(id, Symbol::Local(name.to_string(), home as usize));
} else {
artifact.symbols.insert(id, Symbol::External(name.to_string()));
}
},
Err(_) => {
return Err("Unable to convert string to utf8.".to_string());
}
}
start_byte += 1;
i += 1;
}
if bytes.len() < start_byte + 8 {
return Err("Unable to get size of data section.".to_string());
}
let data_bytes = &bytes[start_byte..start_byte + 7];
let data_size = i64::from_le_bytes([
data_bytes[0],
data_bytes[1],
data_bytes[2],
data_bytes[3],
data_bytes[4],
data_bytes[5],
data_bytes[6],
data_bytes[7],
]);
if bytes.len() < (start_byte + data_size as usize + 1) {
return Err("File is too small for data section.".to_string());
}
let data = &bytes[start_byte..data_size as usize];
artifact.data = data.to_vec();
start_byte += data_size as usize;
let program = &bytes[start_byte..bytes.len() - 1];
artifact.program = program.to_vec();
Ok(artifact)
}
pub fn into_bytes(&mut self) -> Vec<u8> {
let mut bytes: Vec<u8> = vec![
'_' as u8,
'_' as u8,
'v' as u8,
'r' as u8,
'm' as u8,
];
let l = self.symbols.len() as i64;
let le_bytes = l.to_le_bytes();
bytes.append(&mut le_bytes.to_vec());
for symbol in self.symbols.clone() {
let mut id_bytes = symbol.0.to_le_bytes().to_vec();
let mut home_bytes;
let type_byte;
let mut name_bytes;
match symbol.1 {
Symbol::External(n) => {
name_bytes = n.as_bytes().to_vec();
name_bytes.append(&mut vec![0]); home_bytes = vec![0, 0, 0, 0, 0, 0, 0, 0];
type_byte = 1;
},
Symbol::Local(n, home) => {
name_bytes = n.as_bytes().to_vec();
name_bytes.append(&mut vec![0]); home_bytes = home.to_le_bytes().to_vec();
type_byte = 0;
},
}
bytes.append(&mut id_bytes);
bytes.append(&mut home_bytes);
bytes.push(type_byte);
bytes.append(&mut name_bytes);
}
let mut data_len_bytes = self.data.len().to_le_bytes().to_vec();
bytes.append(&mut data_len_bytes);
bytes.append(&mut self.data);
bytes.append(&mut self.program);
bytes
}
}