summaryrefslogtreecommitdiff
path: root/src/translators/bytecode_generator.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/translators/bytecode_generator.rs')
-rw-r--r--src/translators/bytecode_generator.rs131
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) = &macro_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) = &macro_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());
+ }
+}