use crate::*;
use SemanticTokenVariant as SemVar;
pub fn generate_bytecode(semantic_tokens: &mut [SemanticToken]) -> Vec<u8> {
let generator = BytecodeGenerator::from_semantic_tokens(semantic_tokens);
generator.generate()
}
/// Translate semantic tokens into bytecode.
struct BytecodeGenerator<'a> {
semantic_tokens: &'a mut [SemanticToken],
block_stack: Vec<usize>,
bytecode: Vec<u8>,
/// (address in bytecode, label definition token index)
label_references: Vec<(usize, usize)>,
}
impl<'a> BytecodeGenerator<'a> {
pub fn from_semantic_tokens(semantic_tokens: &'a mut [SemanticToken]) -> Self {
Self {
semantic_tokens,
block_stack: Vec::new(),
bytecode: Vec::new(),
label_references: Vec::new(),
}
}
pub fn generate(mut self) -> Vec<u8> {
for i in 0..self.semantic_tokens.len() {
let address = self.bytecode.len();
self.generate_bytecode_for_token(i, None);
self.semantic_tokens[i].bytecode = BytecodeSpan {
bytes: self.bytecode[address..].to_vec(),
location: BytecodeLocation {
address,
length: self.bytecode.len().saturating_sub(address),
}
};
}
// Replace blank label references in bytecode with real label addresses.
// The layer of indirection is necessary because the iteration borrows
// self immutably.
let mut insertions: Vec<(usize, u16)> = Vec::new();
for (bytecode_address, token_pointer) in &self.label_references {
let label_token = &self.semantic_tokens[*token_pointer];
// TODO: If greater than u16, print a warning.
let address_value = label_token.bytecode.location.address as u16;
insertions.push((*bytecode_address, address_value));
}
for (bytecode_address, address_value) in insertions {
self.replace_address_in_bytecode(bytecode_address, address_value);
}
// Strip trailing null bytes from the bytecode.
let mut length = self.bytecode.len();
for (i, byte) in self.bytecode.iter().enumerate().rev() {
match *byte == 0 {
true => length = i,
false => break,
};
}
self.bytecode.truncate(length);
return self.bytecode;
}
fn generate_bytecode_for_token(&mut self, pointer: usize, macro_pointer: Option<usize>) {
macro_rules! push_byte {
($byte:expr) => { self.bytecode.push($byte) }; }
macro_rules! push_double {
($double:expr) => { self.bytecode.extend_from_slice(&$double.to_be_bytes()) }; }
macro_rules! pad {
($len:expr) => { for _ in 0..$len { push_byte!(0); } } }
let semantic_token = if let Some(macro_pointer) = macro_pointer {
let macro_definition = &self.semantic_tokens[macro_pointer];
if let SemVar::MacroDefinition(def) = ¯o_definition.variant {
&def.body_tokens[pointer]
} else { unreachable!() }
} else {
&self.semantic_tokens[pointer]
};
match &semantic_token.variant {
SemVar::MacroInvocation(pointer) => {
let macro_definition = &self.semantic_tokens[*pointer];
if let SemVar::MacroDefinition(def) = ¯o_definition.variant {
let length = def.body_tokens.len();
let macro_pointer = Some(*pointer);
for body_pointer in 0..length {
// Recurse, generate bytecode for each macro body token.
self.generate_bytecode_for_token(body_pointer, macro_pointer);
}
} else { unreachable!() }
}
SemVar::Literal(value) => match value {
Value::Byte(value) => push_byte!(*value),
Value::Double(value) => push_double!(value),
}
SemVar::Padding(value) => match value {
Value::Byte(value) => pad!(*value),
Value::Double(value) => pad!(*value),
}
SemVar::Instruction(instr) => push_byte!(instr.value),
SemVar::String(bytes) => self.bytecode.extend_from_slice(&bytes),
SemVar::LabelReference(pointer) => {
self.label_references.push((self.bytecode.len(), *pointer));
push_double!(0u16);
}
SemVar::BlockOpen(_) => {
self.block_stack.push(self.bytecode.len());
push_double!(0u16);
}
SemVar::BlockClose(_) => {
let bytecode_address = self.block_stack.pop().unwrap();
// TODO: If greater than u16, print a warning.
let address_value = self.bytecode.len() as u16;
self.replace_address_in_bytecode(bytecode_address, address_value);
}
_ => (),
};
}
fn replace_address_in_bytecode(&mut self, bytecode_address: usize, address_value: u16) {
let range = bytecode_address..bytecode_address+2;
self.bytecode[range].clone_from_slice(&address_value.to_be_bytes());
}
}