diff options
Diffstat (limited to 'src/parsers/bytecode.rs')
-rw-r--r-- | src/parsers/bytecode.rs | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/src/parsers/bytecode.rs b/src/parsers/bytecode.rs index ec19d9f..6cdfd3a 100644 --- a/src/parsers/bytecode.rs +++ b/src/parsers/bytecode.rs @@ -25,28 +25,7 @@ impl<'a> BytecodeGenerator<'a> { for token in self.tokens { match token { AssembledToken::Word(assembled_word) => { - let mut value = assembled_word.value; - for field in &assembled_word.fields { - let (field_value, source) = match &field.value { - IntegerArgument::Expression(expr) => - (self.resolve_expression(expr), expr.source.clone()), - IntegerArgument::LabelReference(name) => - (self.resolve_label_reference(name), name.source.clone()), - IntegerArgument::Integer(integer) => - (integer.value, integer.source.clone()), - }; - let bitcount = match field_value { - 0 => 0, - _ => (field_value.ilog2() + 1) as usize, - }; - if field.bits < bitcount { - let variant = BytecodeErrorVariant::ValueTooLarge(field.bits, bitcount); - self.errors.push(BytecodeError { source, variant }); - } else { - value |= (field_value << field.shift) as usize; - } - } - self.words.push(Word { bits: assembled_word.bits, value }); + self.assemble_word(assembled_word); } AssembledToken::PinnedAddress(pinned) => { if self.words.len() > pinned.address { @@ -74,7 +53,7 @@ impl<'a> BytecodeGenerator<'a> { for token in self.tokens { match token { AssembledToken::LabelDefinition(definition) => { - let address = Tracked::from(i, &definition.source); + let address = Tracked::from(i, definition.source.clone()); if let Some(_) = self.addresses.insert(definition.name.clone(), address) { let name = definition.name.clone(); let variant = BytecodeErrorVariant::DuplicateLabelDefinition(name); @@ -82,8 +61,8 @@ impl<'a> BytecodeGenerator<'a> { self.errors.push(BytecodeError { source, variant }); } } - AssembledToken::Word(_) => { - i += 1; + AssembledToken::Word(word) => { + i += word.count(); } AssembledToken::PinnedAddress(pinned) => { i = pinned.address; @@ -158,4 +137,53 @@ impl<'a> BytecodeGenerator<'a> { 0 } } + + fn assemble_word(&mut self, assembled_word: &AssembledWord) { + let mut field_values = Vec::new(); + for field in &assembled_word.fields { + match &field.value { + IntegerArgument::Expression(expr) => { + let source = expr.source.clone(); + let value = self.resolve_expression(expr); + field_values.push(vec![Tracked::from(value, source)]) + } + IntegerArgument::LabelReference(name) => { + let source = name.source.clone(); + let value = self.resolve_label_reference(name); + field_values.push(vec![Tracked::from(value, source)]) + } + IntegerArgument::Integer(integer) => { + let source = integer.source.clone(); + let value = integer.value; + field_values.push(vec![Tracked::from(value, source)]) + } + IntegerArgument::String(string) => { + let values = string.chars.iter() + .map(|c| Tracked::from(c.value as isize, c.source.clone())) + .collect(); + field_values.push(values); + } + }; + } + for i in 0..assembled_word.count() { + let mut value = assembled_word.value; + for (f, field) in assembled_word.fields.iter().enumerate() { + let (field_value, source) = match field_values[f].get(i) { + Some(tracked) => (tracked.value, Some(tracked.source.clone())), + None => (0, None), + }; + let bitcount = match field_value { + 0 => 0, + _ => (field_value.ilog2() + 1) as usize, + }; + if field.bits < bitcount { + let variant = BytecodeErrorVariant::ValueTooLarge(field.bits, bitcount); + self.errors.push(BytecodeError { source: source.unwrap(), variant }); + } else { + value |= (field_value << field.shift) as usize; + } + } + self.words.push(Word { bits: assembled_word.bits, value }); + } + } } |