Implement closing for lists

This commit is contained in:
Jeff 2024-09-17 23:06:58 -04:00
parent 37dc2e05c5
commit 2f8c46f0a5
3 changed files with 36 additions and 14 deletions

View File

@ -15,10 +15,11 @@ impl Instruction {
instruction instruction
} }
pub fn close(to_register: u8) -> Instruction { pub fn close(from_register: u8, to_register: u8) -> Instruction {
let mut instruction = Instruction(Operation::Close as u32); let mut instruction = Instruction(Operation::Close as u32);
instruction.set_destination(to_register); instruction.set_first_argument(from_register);
instruction.set_second_argument(to_register);
instruction instruction
} }
@ -243,7 +244,12 @@ impl Instruction {
Operation::Move => { Operation::Move => {
format!("R({}) = R({})", self.destination(), self.first_argument()) format!("R({}) = R({})", self.destination(), self.first_argument())
} }
Operation::Close => format!("R({})", self.destination()), Operation::Close => {
let from_register = self.first_argument();
let to_register = self.second_argument().saturating_sub(1);
format!("R({from_register})..=R({to_register})")
}
Operation::LoadConstant => { Operation::LoadConstant => {
let constant_index = self.first_argument(); let constant_index = self.first_argument();
@ -274,7 +280,7 @@ impl Instruction {
let last_index = destination - 1; let last_index = destination - 1;
format!( format!(
"R({}) = [R({})..R({})]", "R({}) = [R({})..=R({})]",
destination, first_index, last_index destination, first_index, last_index
) )
} }
@ -556,15 +562,11 @@ mod tests {
#[test] #[test]
fn close() { fn close() {
let mut instruction = Instruction::close(1); let instruction = Instruction::close(1, 2);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Close); assert_eq!(instruction.operation(), Operation::Close);
assert_eq!(instruction.destination(), 1); assert_eq!(instruction.first_argument(), 1);
assert!(instruction.first_argument_is_constant()); assert_eq!(instruction.second_argument(), 2);
assert!(instruction.second_argument_is_constant());
} }
#[test] #[test]

View File

@ -485,8 +485,17 @@ impl<'src> Parser<'src> {
let mut length = 0; let mut length = 0;
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() { while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
let next_register = self.current_register;
self.parse(Precedence::Assignment)?; // Do not allow assignment self.parse(Precedence::Assignment)?; // Do not allow assignment
if next_register != self.current_register - 1 {
self.emit_instruction(
Instruction::close(next_register, self.current_register - 1),
self.current_position,
);
}
length += 1; length += 1;
if !self.allow(TokenKind::Comma)? { if !self.allow(TokenKind::Comma)? {

View File

@ -66,7 +66,14 @@ impl Vm {
self.insert(value, to, position)?; self.insert(value, to, position)?;
} }
Operation::Close => todo!(), Operation::Close => {
let from = instruction.first_argument();
let to = instruction.second_argument();
for register_index in from..to {
self.register_stack[register_index as usize] = None;
}
}
Operation::LoadConstant => { Operation::LoadConstant => {
let to_register = instruction.destination(); let to_register = instruction.destination();
let from_constant = instruction.first_argument(); let from_constant = instruction.first_argument();
@ -77,13 +84,17 @@ impl Vm {
Operation::LoadList => { Operation::LoadList => {
let to_register = instruction.destination(); let to_register = instruction.destination();
let length = instruction.first_argument(); let length = instruction.first_argument();
let first_register = to_register - length; let first_register = to_register - length - 1;
let last_register = to_register - 1; let last_register = to_register - 1;
let mut list = Vec::with_capacity(length as usize); let mut list = Vec::with_capacity(length as usize);
for register_index in first_register..=last_register { for register_index in first_register..=last_register {
let value = self.clone(register_index, position)?; let value = match self.clone(register_index, position) {
Ok(value) => value,
Err(VmError::EmptyRegister { .. }) => continue,
Err(error) => return Err(error),
};
list.push(value); list.push(value);
} }