diff options
Diffstat (limited to 'src/translators/bytecode_generator.rs')
-rw-r--r-- | src/translators/bytecode_generator.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/translators/bytecode_generator.rs b/src/translators/bytecode_generator.rs new file mode 100644 index 0000000..956aca5 --- /dev/null +++ b/src/translators/bytecode_generator.rs @@ -0,0 +1,131 @@ +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()); + } +} |