use crate::*; use SemanticTokenVariant as SemVar; pub fn generate_bytecode(semantic_tokens: &mut [SemanticToken]) -> Vec { 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, bytecode: Vec, /// (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 { 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) { 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()); } }