From 7afde989f92a5b802d35bc6683ef938c8b87dd3c Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 24 Sep 2024 16:49:17 -0400 Subject: [PATCH] Fix bugs in binary parsing and running --- dust-lang/src/chunk.rs | 6 +- dust-lang/src/instruction.rs | 519 +++++++++--------- dust-lang/src/parser/mod.rs | 64 ++- dust-lang/src/parser/tests.rs | 95 ++-- dust-lang/src/vm.rs | 137 ++--- .../tests/{operations.rs => expressions.rs} | 11 +- 6 files changed, 412 insertions(+), 420 deletions(-) rename dust-lang/tests/{operations.rs => expressions.rs} (90%) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 151472a..461227f 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use colored::Colorize; use serde::{Deserialize, Serialize}; -use crate::{instruction, AnnotatedError, Identifier, Instruction, Operation, Span, Value}; +use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Value}; #[derive(Clone)] pub struct Chunk { @@ -76,12 +76,12 @@ impl Chunk { .ok_or(ChunkError::InstructionUnderflow { position }) } - pub fn get_previous(&self) -> Option<&(Instruction, Span)> { + pub fn get_last_instruction(&self) -> Option<&(Instruction, Span)> { self.instructions.last() } pub fn get_last_operation(&self) -> Option { - self.get_previous() + self.get_last_instruction() .map(|(instruction, _)| instruction.operation()) } diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index 17ea06a..b74691c 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -1,5 +1,3 @@ -use std::fmt::{self, format, Display, Formatter}; - use crate::{Chunk, Operation, Span}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -9,8 +7,8 @@ impl Instruction { pub fn r#move(to_register: u8, from_register: u8) -> Instruction { let mut instruction = Instruction(Operation::Move as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(from_register); + instruction.set_a(to_register); + instruction.set_b(from_register); instruction } @@ -18,8 +16,8 @@ impl Instruction { pub fn close(from_register: u8, to_register: u8) -> Instruction { let mut instruction = Instruction(Operation::Close as u32); - instruction.set_first_argument(from_register); - instruction.set_second_argument(to_register); + instruction.set_b(from_register); + instruction.set_c(to_register); instruction } @@ -27,9 +25,9 @@ impl Instruction { pub fn load_boolean(to_register: u8, value: bool, skip: bool) -> Instruction { let mut instruction = Instruction(Operation::LoadBoolean as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(if value { 1 } else { 0 }); - instruction.set_second_argument(if skip { 1 } else { 0 }); + instruction.set_a(to_register); + instruction.set_b(if value { 1 } else { 0 }); + instruction.set_c(if skip { 1 } else { 0 }); instruction } @@ -37,8 +35,8 @@ impl Instruction { pub fn load_constant(to_register: u8, constant_index: u8) -> Instruction { let mut instruction = Instruction(Operation::LoadConstant as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(constant_index); + instruction.set_a(to_register); + instruction.set_b(constant_index); instruction } @@ -46,9 +44,9 @@ impl Instruction { pub fn load_list(to_register: u8, start_register: u8, list_length: u8) -> Instruction { let mut instruction = Instruction(Operation::LoadList as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(start_register); - instruction.set_second_argument(list_length); + instruction.set_a(to_register); + instruction.set_b(start_register); + instruction.set_c(list_length); instruction } @@ -56,9 +54,9 @@ impl Instruction { pub fn define_local(to_register: u8, local_index: u8, is_mutable: bool) -> Instruction { let mut instruction = Instruction(Operation::DefineLocal as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(local_index); - instruction.set_second_argument(if is_mutable { 1 } else { 0 }); + instruction.set_a(to_register); + instruction.set_b(local_index); + instruction.set_c(if is_mutable { 1 } else { 0 }); instruction } @@ -66,8 +64,8 @@ impl Instruction { pub fn get_local(to_register: u8, local_index: u8) -> Instruction { let mut instruction = Instruction(Operation::GetLocal as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(local_index); + instruction.set_a(to_register); + instruction.set_b(local_index); instruction } @@ -75,8 +73,8 @@ impl Instruction { pub fn set_local(from_register: u8, local_index: u8) -> Instruction { let mut instruction = Instruction(Operation::SetLocal as u32); - instruction.set_destination(from_register); - instruction.set_first_argument(local_index); + instruction.set_a(from_register); + instruction.set_b(local_index); instruction } @@ -84,9 +82,9 @@ impl Instruction { pub fn add(to_register: u8, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Add as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(to_register); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -94,9 +92,9 @@ impl Instruction { pub fn subtract(to_register: u8, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Subtract as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(to_register); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -104,9 +102,9 @@ impl Instruction { pub fn multiply(to_register: u8, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Multiply as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(to_register); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -114,9 +112,9 @@ impl Instruction { pub fn divide(to_register: u8, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Divide as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(to_register); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -124,9 +122,9 @@ impl Instruction { pub fn modulo(to_register: u8, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Modulo as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(to_register); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -134,8 +132,8 @@ impl Instruction { pub fn test(to_register: u8, test_value: bool) -> Instruction { let mut instruction = Instruction(Operation::Test as u32); - instruction.set_destination(to_register); - instruction.set_second_argument_to_boolean(test_value); + instruction.set_a(to_register); + instruction.set_c_to_boolean(test_value); instruction } @@ -143,9 +141,9 @@ impl Instruction { pub fn test_set(to_register: u8, argument_index: u8, test_value: bool) -> Instruction { let mut instruction = Instruction(Operation::TestSet as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(argument_index); - instruction.set_second_argument_to_boolean(test_value); + instruction.set_a(to_register); + instruction.set_b(argument_index); + instruction.set_c_to_boolean(test_value); instruction } @@ -153,9 +151,9 @@ impl Instruction { pub fn equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Equal as u32); - instruction.set_destination(if comparison_boolean { 1 } else { 0 }); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(if comparison_boolean { 1 } else { 0 }); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -163,9 +161,9 @@ impl Instruction { pub fn less(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Less as u32); - instruction.set_destination(if comparison_boolean { 1 } else { 0 }); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(if comparison_boolean { 1 } else { 0 }); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -173,9 +171,9 @@ impl Instruction { pub fn less_equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction { let mut instruction = Instruction(Operation::LessEqual as u32); - instruction.set_destination(if comparison_boolean { 1 } else { 0 }); - instruction.set_first_argument(left_index); - instruction.set_second_argument(right_index); + instruction.set_a(if comparison_boolean { 1 } else { 0 }); + instruction.set_b(left_index); + instruction.set_c(right_index); instruction } @@ -183,8 +181,8 @@ impl Instruction { pub fn negate(to_register: u8, from_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Negate as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(from_index); + instruction.set_a(to_register); + instruction.set_b(from_index); instruction } @@ -192,8 +190,8 @@ impl Instruction { pub fn not(to_register: u8, from_index: u8) -> Instruction { let mut instruction = Instruction(Operation::Not as u32); - instruction.set_destination(to_register); - instruction.set_first_argument(from_index); + instruction.set_a(to_register); + instruction.set_b(from_index); instruction } @@ -201,8 +199,8 @@ impl Instruction { pub fn jump(offset: u8, is_positive: bool) -> Instruction { let mut instruction = Instruction(Operation::Jump as u32); - instruction.set_first_argument(offset); - instruction.set_second_argument(if is_positive { 1 } else { 0 }); + instruction.set_b(offset); + instruction.set_c(if is_positive { 1 } else { 0 }); instruction } @@ -210,8 +208,8 @@ impl Instruction { pub fn r#return(from_register: u8, to_register: u8) -> Instruction { let mut instruction = Instruction(Operation::Return as u32); - instruction.set_destination(from_register); - instruction.set_first_argument(to_register); + instruction.set_a(from_register); + instruction.set_b(to_register); instruction } @@ -219,7 +217,7 @@ impl Instruction { pub fn end(returns_value: bool) -> Instruction { let mut instruction = Instruction(Operation::End as u32); - instruction.set_destination_to_boolean(returns_value); + instruction.set_a_to_boolean(returns_value); instruction } @@ -232,92 +230,102 @@ impl Instruction { self.0 |= u8::from(operation) as u32; } - pub fn destination(&self) -> u8 { + pub fn data(&self) -> (Operation, u8, u8, u8, bool, bool) { + ( + self.operation(), + self.a(), + self.b(), + self.c(), + self.b_is_constant(), + self.c_is_constant(), + ) + } + + pub fn a(&self) -> u8 { (self.0 >> 24) as u8 } - pub fn destination_as_boolean(&self) -> bool { - (self.0 >> 24) != 0 - } - - pub fn set_destination_to_boolean(&mut self, boolean: bool) -> &mut Self { - self.set_destination(if boolean { 1 } else { 0 }); - - self - } - - pub fn set_destination(&mut self, destination: u8) { - self.0 &= 0x00FFFFFF; - self.0 |= (destination as u32) << 24; - } - - pub fn first_argument(&self) -> u8 { + pub fn b(&self) -> u8 { (self.0 >> 16) as u8 } - pub fn first_argument_is_constant(&self) -> bool { - self.0 & 0b1000_0000 != 0 + pub fn c(&self) -> u8 { + (self.0 >> 8) as u8 } - pub fn first_argument_as_boolean(&self) -> bool { - self.first_argument() != 0 + pub fn a_as_boolean(&self) -> bool { + self.a() != 0 } - pub fn set_first_argument_to_boolean(&mut self, boolean: bool) -> &mut Self { - self.set_first_argument(if boolean { 1 } else { 0 }); + pub fn b_as_boolean(&self) -> bool { + self.b() != 0 + } + + pub fn c_as_boolean(&self) -> bool { + self.c() != 0 + } + + pub fn set_a_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.set_a(if boolean { 1 } else { 0 }); self } - pub fn set_first_argument_to_constant(&mut self) -> &mut Self { + pub fn set_b_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.set_b(if boolean { 1 } else { 0 }); + + self + } + + pub fn set_c_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.set_c(if boolean { 1 } else { 0 }); + + self + } + + pub fn set_a(&mut self, destination: u8) { + self.0 |= (destination as u32) << 24; + } + + pub fn set_b(&mut self, argument: u8) { + self.0 |= (argument as u32) << 16; + } + + pub fn set_c(&mut self, argument: u8) { + self.0 |= (argument as u32) << 8; + } + + pub fn b_is_constant(&self) -> bool { + self.0 & 0b1000_0000 != 0 + } + + pub fn c_is_constant(&self) -> bool { + self.0 & 0b0100_0000 != 0 + } + + pub fn set_b_is_constant(&mut self) -> &mut Self { self.0 |= 0b1000_0000; self } - pub fn set_first_argument(&mut self, argument: u8) { - self.0 |= (argument as u32) << 16; - } - - pub fn second_argument(&self) -> u8 { - (self.0 >> 8) as u8 - } - - pub fn second_argument_is_constant(&self) -> bool { - self.0 & 0b0100_0000 != 0 - } - - pub fn second_argument_as_boolean(&self) -> bool { - self.second_argument() != 0 - } - - pub fn set_second_argument_to_boolean(&mut self, boolean: bool) -> &mut Self { - self.set_second_argument(if boolean { 1 } else { 0 }); - - self - } - - pub fn set_second_argument_to_constant(&mut self) -> &mut Self { + pub fn set_c_is_constant(&mut self) -> &mut Self { self.0 |= 0b0100_0000; self } - pub fn set_second_argument(&mut self, argument: u8) { - self.0 |= (argument as u32) << 8; - } - pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> (Option, Option) { let format_arguments = || { - let first_argument = if self.first_argument_is_constant() { - format!("C{}", self.first_argument()) + let first_argument = if self.b_is_constant() { + format!("C{}", self.b()) } else { - format!("R{}", self.first_argument()) + format!("R{}", self.b()) }; - let second_argument = if self.second_argument_is_constant() { - format!("C{}", self.second_argument()) + let second_argument = if self.c_is_constant() { + format!("C{}", self.c()) } else { - format!("R{}", self.second_argument()) + format!("R{}", self.c()) }; (first_argument, second_argument) @@ -325,21 +333,17 @@ impl Instruction { let mut jump_offset = None; let info = match self.operation() { - Operation::Move => Some(format!( - "R{} = R{}", - self.destination(), - self.first_argument() - )), + Operation::Move => Some(format!("R{} = R{}", self.a(), self.b())), Operation::Close => { - let from_register = self.first_argument(); - let to_register = self.second_argument().saturating_sub(1); + let from_register = self.b(); + let to_register = self.c().saturating_sub(1); Some(format!("R{from_register}..=R{to_register}")) } Operation::LoadBoolean => { - let to_register = self.destination(); - let boolean = self.first_argument_as_boolean(); - let jump = self.second_argument_as_boolean(); + let to_register = self.a(); + let boolean = self.b_as_boolean(); + let jump = self.c_as_boolean(); let info = if jump { jump_offset = Some(1); @@ -351,30 +355,22 @@ impl Instruction { Some(info) } Operation::LoadConstant => { - let constant_index = self.first_argument(); + let constant_index = self.b(); if let Some(chunk) = chunk { match chunk.get_constant(constant_index, Span(0, 0)) { - Ok(value) => Some(format!( - "R{} = C{} {}", - self.destination(), - constant_index, - value - )), - Err(error) => Some(format!( - "R{} = C{} {:?}", - self.destination(), - constant_index, - error - )), + Ok(value) => Some(format!("R{} = C{} {}", self.a(), constant_index, value)), + Err(error) => { + Some(format!("R{} = C{} {:?}", self.a(), constant_index, error)) + } } } else { - Some(format!("R{} = C{}", self.destination(), constant_index)) + Some(format!("R{} = C{}", self.a(), constant_index)) } } Operation::LoadList => { - let destination = self.destination(); - let first_index = self.first_argument(); + let destination = self.a(); + let first_index = self.b(); let last_index = destination.saturating_sub(1); Some(format!( @@ -383,8 +379,8 @@ impl Instruction { )) } Operation::DefineLocal => { - let destination = self.destination(); - let local_index = self.first_argument(); + let destination = self.a(); + let local_index = self.b(); let identifier_display = if let Some(chunk) = chunk { match chunk.get_identifier(local_index) { Some(identifier) => identifier.to_string(), @@ -393,23 +389,19 @@ impl Instruction { } else { "???".to_string() }; - let mutable_display = if self.second_argument_as_boolean() { - "mut " - } else { - "" - }; + let mutable_display = if self.c_as_boolean() { "mut " } else { "" }; Some(format!( "L{local_index} = R{destination} {mutable_display}{identifier_display}" )) } Operation::GetLocal => { - let local_index = self.first_argument(); + let local_index = self.b(); - Some(format!("R{} = L{}", self.destination(), local_index)) + Some(format!("R{} = L{}", self.a(), local_index)) } Operation::SetLocal => { - let local_index = self.first_argument(); + let local_index = self.b(); let identifier_display = if let Some(chunk) = chunk { match chunk.get_identifier(local_index) { Some(identifier) => identifier.to_string(), @@ -422,12 +414,12 @@ impl Instruction { Some(format!( "L{} = R{} {}", local_index, - self.destination(), + self.a(), identifier_display )) } Operation::Add => { - let destination = self.destination(); + let destination = self.a(); let (first_argument, second_argument) = format_arguments(); Some(format!( @@ -435,7 +427,7 @@ impl Instruction { )) } Operation::Subtract => { - let destination = self.destination(); + let destination = self.a(); let (first_argument, second_argument) = format_arguments(); Some(format!( @@ -443,7 +435,7 @@ impl Instruction { )) } Operation::Multiply => { - let destination = self.destination(); + let destination = self.a(); let (first_argument, second_argument) = format_arguments(); Some(format!( @@ -451,7 +443,7 @@ impl Instruction { )) } Operation::Divide => { - let destination = self.destination(); + let destination = self.a(); let (first_argument, second_argument) = format_arguments(); Some(format!( @@ -459,7 +451,7 @@ impl Instruction { )) } Operation::Modulo => { - let destination = self.destination(); + let destination = self.a(); let (first_argument, second_argument) = format_arguments(); Some(format!( @@ -467,18 +459,17 @@ impl Instruction { )) } Operation::Test => { - let destination = self.destination(); - let test_value = self.second_argument_as_boolean(); - let bang = if test_value { "" } else { "!" }; + let destination = self.a(); + let test_value = self.c_as_boolean(); jump_offset = Some(1); - Some(format!("if {bang}R{destination}",)) + Some(format!("if R{destination} != {test_value} {{ JUMP }}",)) } Operation::TestSet => { - let destination = self.destination(); - let argument = format!("R{}", self.first_argument()); - let test_value = self.second_argument_as_boolean(); + let destination = self.a(); + let argument = format!("R{}", self.b()); + let test_value = self.c_as_boolean(); let bang = if test_value { "" } else { "!" }; jump_offset = Some(1); @@ -488,11 +479,7 @@ impl Instruction { )) } Operation::Equal => { - let comparison_symbol = if self.destination_as_boolean() { - "==" - } else { - "!=" - }; + let comparison_symbol = if self.a_as_boolean() { "==" } else { "!=" }; let (first_argument, second_argument) = format_arguments(); jump_offset = Some(1); @@ -502,11 +489,7 @@ impl Instruction { )) } Operation::Less => { - let comparison_symbol = if self.destination_as_boolean() { - "<" - } else { - ">=" - }; + let comparison_symbol = if self.a_as_boolean() { "<" } else { ">=" }; let (first_argument, second_argument) = format_arguments(); jump_offset = Some(1); @@ -515,11 +498,7 @@ impl Instruction { )) } Operation::LessEqual => { - let comparison_symbol = if self.destination_as_boolean() { - "<=" - } else { - ">" - }; + let comparison_symbol = if self.a_as_boolean() { "<=" } else { ">" }; let (first_argument, second_argument) = format_arguments(); jump_offset = Some(1); @@ -528,28 +507,28 @@ impl Instruction { )) } Operation::Negate => { - let destination = self.destination(); - let argument = if self.first_argument_is_constant() { - format!("C{}", self.first_argument()) + let destination = self.a(); + let argument = if self.b_is_constant() { + format!("C{}", self.b()) } else { - format!("R{}", self.first_argument()) + format!("R{}", self.b()) }; Some(format!("R{destination} = -{argument}")) } Operation::Not => { - let destination = self.destination(); - let argument = if self.first_argument_is_constant() { - format!("C{}", self.first_argument()) + let destination = self.a(); + let argument = if self.b_is_constant() { + format!("C{}", self.b()) } else { - format!("R{}", self.first_argument()) + format!("R{}", self.b()) }; Some(format!("R{destination} = !{argument}")) } Operation::Jump => { - let offset = self.first_argument() as isize; - let is_positive = self.second_argument_as_boolean(); + let offset = self.b() as isize; + let is_positive = self.c_as_boolean(); if is_positive { jump_offset = Some(offset); @@ -560,13 +539,13 @@ impl Instruction { None } Operation::Return => { - let from_register = self.destination(); - let to_register = self.first_argument(); + let from_register = self.a(); + let to_register = self.b(); Some(format!("R{from_register}..=R{to_register}")) } Operation::End => { - let return_value = self.destination_as_boolean(); + let return_value = self.a_as_boolean(); if return_value { Some("return".to_string()) @@ -594,14 +573,14 @@ mod tests { fn r#move() { let mut instruction = Instruction::r#move(0, 1); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Move); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] @@ -609,8 +588,8 @@ mod tests { let instruction = Instruction::close(1, 2); assert_eq!(instruction.operation(), Operation::Close); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 2); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 2); } #[test] @@ -618,94 +597,94 @@ mod tests { let instruction = Instruction::load_boolean(4, true, true); assert_eq!(instruction.operation(), Operation::LoadBoolean); - assert_eq!(instruction.destination(), 4); - assert!(instruction.first_argument_as_boolean()); - assert!(instruction.second_argument_as_boolean()); + assert_eq!(instruction.a(), 4); + assert!(instruction.a_as_boolean()); + assert!(instruction.c_as_boolean()); } #[test] fn load_constant() { let mut instruction = Instruction::load_constant(0, 1); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::LoadConstant); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] fn declare_local() { let mut instruction = Instruction::define_local(0, 1, true); - instruction.set_first_argument_to_constant(); + instruction.set_b_is_constant(); assert_eq!(instruction.operation(), Operation::DefineLocal); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), true as u8); - assert!(instruction.first_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), true as u8); + assert!(instruction.b_is_constant()); } #[test] fn add() { let mut instruction = Instruction::add(1, 1, 0); - instruction.set_first_argument_to_constant(); + instruction.set_b_is_constant(); assert_eq!(instruction.operation(), Operation::Add); - assert_eq!(instruction.destination(), 1); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 0); - assert!(instruction.first_argument_is_constant()); + assert_eq!(instruction.a(), 1); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 0); + assert!(instruction.b_is_constant()); } #[test] fn subtract() { let mut instruction = Instruction::subtract(0, 1, 2); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Subtract); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 2); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 2); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] fn multiply() { let mut instruction = Instruction::multiply(0, 1, 2); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Multiply); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 2); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 2); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] fn divide() { let mut instruction = Instruction::divide(0, 1, 2); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Divide); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 2); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 2); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] @@ -713,8 +692,8 @@ mod tests { let instruction = Instruction::test(4, true); assert_eq!(instruction.operation(), Operation::Test); - assert_eq!(instruction.destination(), 4); - assert!(instruction.second_argument_as_boolean()); + assert_eq!(instruction.a(), 4); + assert!(instruction.c_as_boolean()); } #[test] @@ -722,52 +701,52 @@ mod tests { let instruction = Instruction::test_set(4, 1, true); assert_eq!(instruction.operation(), Operation::TestSet); - assert_eq!(instruction.destination(), 4); - assert_eq!(instruction.first_argument(), 1); - assert!(instruction.second_argument_as_boolean()); + assert_eq!(instruction.a(), 4); + assert_eq!(instruction.b(), 1); + assert!(instruction.c_as_boolean()); } #[test] fn equal() { let mut instruction = Instruction::equal(true, 1, 2); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Equal); - assert!(instruction.destination_as_boolean()); - assert_eq!(instruction.first_argument(), 1); - assert_eq!(instruction.second_argument(), 2); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert!(instruction.a_as_boolean()); + assert_eq!(instruction.b(), 1); + assert_eq!(instruction.c(), 2); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] fn negate() { let mut instruction = Instruction::negate(0, 1); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Negate); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] fn not() { let mut instruction = Instruction::not(0, 1); - instruction.set_first_argument_to_constant(); - instruction.set_second_argument_to_constant(); + instruction.set_b_is_constant(); + instruction.set_c_is_constant(); assert_eq!(instruction.operation(), Operation::Not); - assert_eq!(instruction.destination(), 0); - assert_eq!(instruction.first_argument(), 1); - assert!(instruction.first_argument_is_constant()); - assert!(instruction.second_argument_is_constant()); + assert_eq!(instruction.a(), 0); + assert_eq!(instruction.b(), 1); + assert!(instruction.b_is_constant()); + assert!(instruction.b_is_constant()); } #[test] @@ -775,8 +754,8 @@ mod tests { let instruction = Instruction::jump(4, true); assert_eq!(instruction.operation(), Operation::Jump); - assert_eq!(instruction.first_argument(), 4); - assert!(instruction.first_argument_as_boolean()); + assert_eq!(instruction.b(), 4); + assert!(instruction.c_as_boolean()); } #[test] @@ -784,8 +763,8 @@ mod tests { let instruction = Instruction::r#return(4, 8); assert_eq!(instruction.operation(), Operation::Return); - assert_eq!(instruction.destination(), 4); - assert_eq!(instruction.first_argument(), 8); + assert_eq!(instruction.a(), 4); + assert_eq!(instruction.b(), 8); } #[test] @@ -793,6 +772,6 @@ mod tests { let instruction = Instruction::end(true); assert_eq!(instruction.operation(), Operation::End); - assert!(instruction.destination_as_boolean()); + assert!(instruction.a_as_boolean()); } } diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index dcd2119..7ea1ea1 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -293,16 +293,16 @@ impl<'src> Parser<'src> { let (push_back, is_constant, argument) = { match previous_instruction.operation() { - Operation::GetLocal => (false, false, previous_instruction.destination()), - Operation::LoadConstant => (false, true, previous_instruction.first_argument()), - Operation::LoadBoolean => (true, false, previous_instruction.destination()), + Operation::GetLocal => (false, false, previous_instruction.a()), + Operation::LoadConstant => (false, true, previous_instruction.a()), + Operation::LoadBoolean => (true, false, previous_instruction.a()), Operation::Close => { return Err(ParseError::ExpectedExpression { found: self.previous_token.to_owned(), position: self.previous_position, }); } - _ => (true, false, previous_instruction.destination()), + _ => (true, false, previous_instruction.a()), } }; @@ -323,7 +323,7 @@ impl<'src> Parser<'src> { }; if is_constant { - instruction.set_first_argument_to_constant(); + instruction.set_b_is_constant(); } if push_back { @@ -342,13 +342,13 @@ impl<'src> Parser<'src> { let mut push_back = false; let mut is_constant = false; let argument = match instruction.operation() { - Operation::GetLocal => instruction.destination(), + Operation::GetLocal => instruction.a(), Operation::LoadConstant => { is_constant = true; - instruction.first_argument() + instruction.b() } - Operation::LoadBoolean => instruction.destination(), + Operation::LoadBoolean => instruction.a(), Operation::Close => { return Err(ParseError::ExpectedExpression { found: self.previous_token.to_owned(), @@ -358,7 +358,7 @@ impl<'src> Parser<'src> { _ => { push_back = true; - instruction.destination() + instruction.a() } }; @@ -406,14 +406,14 @@ impl<'src> Parser<'src> { let (push_back_right, right_is_constant, right) = self.handle_binary_argument(&right_instruction)?; - new_instruction.set_second_argument(right); + new_instruction.set_c(right); if left_is_constant { - new_instruction.set_first_argument_to_constant(); + new_instruction.set_b_is_constant(); } if right_is_constant { - new_instruction.set_second_argument_to_constant(); + new_instruction.set_c_is_constant(); } let mut instructions = if !push_back_left && !push_back_right { @@ -448,9 +448,9 @@ impl<'src> Parser<'src> { } } - instructions.sort_by_key(|(instruction, _)| instruction.destination()); + instructions.sort_by_key(|(instruction, _)| instruction.a()); - for (instruction, position) in instructions { + for (mut instruction, position) in instructions { self.emit_instruction(instruction, position); } @@ -512,14 +512,14 @@ impl<'src> Parser<'src> { let (push_back_right, right_is_constant, right) = self.handle_binary_argument(&right_instruction)?; - instruction.set_second_argument(right); + instruction.set_c(right); if left_is_constant { - instruction.set_first_argument_to_constant(); + instruction.set_b_is_constant(); } if right_is_constant { - instruction.set_second_argument_to_constant(); + instruction.set_c_is_constant(); } if push_back_left || push_back_right { @@ -555,10 +555,9 @@ impl<'src> Parser<'src> { let operator_position = self.current_position; let rule = ParseRule::from(&operator.kind()); - let test_register = left_instruction.destination(); let instruction = match operator.kind() { - TokenKind::DoubleAmpersand => Instruction::test(test_register, true), - TokenKind::DoublePipe => Instruction::test(test_register, false), + TokenKind::DoubleAmpersand => Instruction::test(left_instruction.a(), false), + TokenKind::DoublePipe => Instruction::test(left_instruction.a(), true), _ => { return Err(ParseError::ExpectedTokenMultiple { expected: &[TokenKind::DoubleAmpersand, TokenKind::DoublePipe], @@ -619,7 +618,7 @@ impl<'src> Parser<'src> { if let Some(register_index) = previous_register { log::trace!("Condensing SET_LOCAL to binary expression"); - previous_instruction.set_destination(register_index); + previous_instruction.set_a(register_index); self.emit_instruction(previous_instruction, self.current_position); return Ok(()); @@ -747,11 +746,11 @@ impl<'src> Parser<'src> { self.current_position }; - if let [Some(Operation::LoadBoolean)] = self.chunk.get_last_n_operations() { + if let Some(Operation::LoadBoolean) = self.chunk.get_last_operation() { let (mut load_boolean, load_boolean_position) = self.chunk.pop_instruction(self.current_position)?; - load_boolean.set_second_argument_to_boolean(true); + load_boolean.set_c_to_boolean(true); self.emit_instruction(load_boolean, load_boolean_position); self.increment_register()?; @@ -764,7 +763,7 @@ impl<'src> Parser<'src> { } let jump_end = self.chunk.len(); - let jump_distance = jump_end - jump_start; + let jump_distance = jump_end.saturating_sub(jump_start); self.chunk.insert_instruction( jump_start, @@ -859,15 +858,14 @@ impl<'src> Parser<'src> { self.parse_expression()?; self.increment_register()?; - let (previous_instruction, previous_position) = - *self - .chunk - .get_previous() - .ok_or_else(|| ParseError::ExpectedExpression { - found: self.current_token.to_owned(), - position, - })?; - let register = previous_instruction.destination(); + let (previous_instruction, previous_position) = *self + .chunk + .get_last_instruction() + .ok_or_else(|| ParseError::ExpectedExpression { + found: self.current_token.to_owned(), + position, + })?; + let register = previous_instruction.a(); let local_index = self.chunk .declare_local(identifier, is_mutable, register, previous_position)?; diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index aa47a84..8b8d62d 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -28,10 +28,7 @@ fn negate() { parse(source), Ok(Chunk::with_data( vec![ - ( - *Instruction::negate(0, 0).set_first_argument_to_constant(), - Span(0, 1) - ), + (*Instruction::negate(0, 0).set_b_is_constant(), Span(0, 1)), (Instruction::end(true), Span(5, 5)) ], vec![Value::integer(42)], @@ -50,8 +47,8 @@ fn greater_than_or_equal() { vec![ ( *Instruction::less(false, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 4) ), (Instruction::jump(1, true), Span(2, 4)), @@ -75,8 +72,8 @@ fn greater() { vec![ ( *Instruction::less_equal(false, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::jump(1, true), Span(2, 3)), @@ -100,8 +97,8 @@ fn less_than_or_equal() { vec![ ( *Instruction::less_equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 4) ), (Instruction::jump(1, true), Span(2, 4)), @@ -125,8 +122,8 @@ fn less_than() { vec![ ( *Instruction::less(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::jump(1, true), Span(2, 3)), @@ -150,8 +147,8 @@ fn not_equal() { vec![ ( *Instruction::equal(false, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 4) ), (Instruction::jump(1, true), Span(2, 4)), @@ -175,8 +172,8 @@ fn equal() { vec![ ( *Instruction::equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 4) ), (Instruction::jump(1, true), Span(2, 4)), @@ -200,8 +197,8 @@ fn equality_assignment_long() { vec![ ( *Instruction::equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(13, 15) ), (Instruction::jump(2, true), Span(13, 15)), @@ -228,8 +225,8 @@ fn equality_assignment_short() { vec![ ( *Instruction::equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(10, 12) ), (Instruction::jump(1, true), Span(10, 12)), @@ -254,8 +251,8 @@ fn if_expression() { vec![ ( *Instruction::equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(5, 7) ), (Instruction::jump(2, true), Span(5, 7)), @@ -279,8 +276,8 @@ fn if_else_expression() { vec![ ( *Instruction::equal(true, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(5, 7) ), (Instruction::jump(2, true), Span(5, 7)), @@ -312,14 +309,14 @@ fn list_with_complex_expression() { (Instruction::load_constant(0, 0), Span(1, 2)), ( *Instruction::add(1, 1, 2) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(6, 7) ), ( *Instruction::multiply(2, 3, 4) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(14, 15) ), (Instruction::subtract(3, 1, 2), Span(10, 11)), @@ -350,8 +347,8 @@ fn list_with_simple_expression() { (Instruction::load_constant(0, 0), Span(1, 2)), ( *Instruction::add(1, 1, 2) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(6, 7) ), (Instruction::load_constant(2, 3), Span(11, 12)), @@ -470,12 +467,12 @@ fn parentheses_precedence() { vec![ ( *Instruction::add(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(3, 4) ), ( - *Instruction::multiply(1, 0, 2).set_second_argument_to_constant(), + *Instruction::multiply(1, 0, 2).set_c_is_constant(), Span(8, 9) ), (Instruction::end(true), Span(11, 11)), @@ -494,18 +491,18 @@ fn math_operator_precedence() { vec![ ( *Instruction::add(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), ( *Instruction::multiply(1, 2, 3) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(10, 11) ), ( - *Instruction::divide(2, 1, 4).set_second_argument_to_constant(), + *Instruction::divide(2, 1, 4).set_c_is_constant(), Span(14, 15) ), (Instruction::subtract(3, 0, 2), Span(6, 7)), @@ -546,7 +543,7 @@ fn or() { Ok(Chunk::with_data( vec![ (Instruction::load_boolean(0, true, false), Span(0, 4)), - (Instruction::test(0, false), Span(5, 7)), + (Instruction::test(0, true), Span(5, 7)), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_boolean(1, false, false), Span(8, 13)), (Instruction::end(true), Span(13, 13)), @@ -564,7 +561,7 @@ fn and() { Ok(Chunk::with_data( vec![ (Instruction::load_boolean(0, true, false), Span(0, 4)), - (Instruction::test(0, true), Span(5, 7)), + (Instruction::test(0, false), Span(5, 7)), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_boolean(1, false, false), Span(8, 13)), (Instruction::end(true), Span(13, 13)), @@ -586,7 +583,7 @@ fn variable_and() { (Instruction::load_boolean(1, false, false), Span(22, 27)), (Instruction::define_local(1, 1, false), Span(18, 19)), (Instruction::get_local(2, 0), Span(29, 30)), - (Instruction::test(2, true), Span(31, 33)), + (Instruction::test(2, false), Span(31, 33)), (Instruction::jump(1, true), Span(31, 33)), (Instruction::get_local(3, 1), Span(34, 35)), (Instruction::end(true), Span(35, 35)), @@ -608,8 +605,8 @@ fn divide() { vec![ ( *Instruction::divide(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::end(true), Span(5, 5)), @@ -628,8 +625,8 @@ fn multiply() { vec![ ( *Instruction::multiply(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::end(true), Span(5, 5)), @@ -648,8 +645,8 @@ fn add() { vec![ ( *Instruction::add(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::end(true), Span(5, 5)), @@ -668,8 +665,8 @@ fn subtract() { vec![ ( *Instruction::subtract(0, 0, 1) - .set_first_argument_to_constant() - .set_second_argument_to_constant(), + .set_b_is_constant() + .set_c_is_constant(), Span(2, 3) ), (Instruction::end(true), Span(5, 5)), diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 8f5c573..f82be12 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -41,17 +41,15 @@ impl Vm { instruction: Instruction, position: Span, ) -> Result<(&Value, &Value), VmError> { - let left = if instruction.first_argument_is_constant() { - vm.chunk - .get_constant(instruction.first_argument(), position)? + let left = if instruction.b_is_constant() { + vm.chunk.get_constant(instruction.b(), position)? } else { - vm.get(instruction.first_argument(), position)? + vm.get(instruction.b(), position)? }; - let right = if instruction.second_argument_is_constant() { - vm.chunk - .get_constant(instruction.second_argument(), position)? + let right = if instruction.c_is_constant() { + vm.chunk.get_constant(instruction.c(), position)? } else { - vm.get(instruction.second_argument(), position)? + vm.get(instruction.c(), position)? }; Ok((left, right)) @@ -66,24 +64,24 @@ impl Vm { match instruction.operation() { Operation::Move => { - let from = instruction.first_argument(); - let to = instruction.destination(); + let from = instruction.b(); + let to = instruction.a(); let value = self.take(from, position)?; self.insert(value, to, position)?; } Operation::Close => { - let from = instruction.first_argument(); - let to = instruction.second_argument(); + let from = instruction.b(); + let to = instruction.c(); for register_index in from..to { self.register_stack[register_index as usize] = None; } } Operation::LoadBoolean => { - let to_register = instruction.destination(); - let boolean = instruction.first_argument_as_boolean(); - let skip = instruction.second_argument_as_boolean(); + let to_register = instruction.a(); + let boolean = instruction.b_as_boolean(); + let skip = instruction.c_as_boolean(); let value = Value::boolean(boolean); self.insert(value, to_register, position)?; @@ -93,20 +91,18 @@ impl Vm { } } Operation::LoadConstant => { - let to_register = instruction.destination(); - let from_constant = instruction.first_argument(); + let to_register = instruction.a(); + let from_constant = instruction.b(); let value = self.chunk.take_constant(from_constant, position)?; self.insert(value, to_register, position)?; } Operation::LoadList => { - let to_register = instruction.destination(); - let first_register = instruction.first_argument(); - let length = instruction.second_argument(); + let to_register = instruction.a(); + let first_register = instruction.b(); + let length = instruction.c(); let last_register = first_register + length + 1; - println!("{first_register}..={last_register}"); - let mut list = Vec::with_capacity(length as usize); for register_index in first_register..=last_register { @@ -122,25 +118,25 @@ impl Vm { self.insert(Value::list(list), to_register, position)?; } Operation::DefineLocal => { - let from_register = instruction.destination(); - let to_local = instruction.first_argument(); + let from_register = instruction.a(); + let to_local = instruction.b(); self.chunk.define_local(to_local, from_register, position)?; } Operation::GetLocal => { - let register_index = instruction.destination(); - let local_index = instruction.first_argument(); + let register_index = instruction.a(); + let local_index = instruction.b(); let local = self.chunk.get_local(local_index, position)?.clone(); let value = self.clone_as_variable(local, position)?; self.insert(value, register_index, position)?; } Operation::SetLocal => { - let register_index = instruction.destination(); - let local_index = instruction.first_argument(); + let register_index = instruction.a(); + let local_index = instruction.b(); let local = self.chunk.get_local(local_index, position)?.clone(); let value = self.clone_as_variable(local, position)?; - let new_value = if instruction.first_argument_is_constant() { + let new_value = if instruction.b_is_constant() { self.chunk.take_constant(register_index, position)? } else { self.clone(register_index, position)? @@ -154,61 +150,76 @@ impl Vm { } Operation::Add => { let (left, right) = get_arguments(self, instruction, position)?; + + log::debug!("{left} + {right}"); + let sum = left .add(right) .map_err(|error| VmError::Value { error, position })?; - self.insert(sum, instruction.destination(), position)?; + self.insert(sum, instruction.a(), position)?; } Operation::Subtract => { let (left, right) = get_arguments(self, instruction, position)?; + + log::debug!("{left} - {right}"); + let difference = left .subtract(right) .map_err(|error| VmError::Value { error, position })?; - self.insert(difference, instruction.destination(), position)?; + self.insert(difference, instruction.a(), position)?; } Operation::Multiply => { let (left, right) = get_arguments(self, instruction, position)?; + + log::debug!("{left} * {right}"); + let product = left .multiply(right) .map_err(|error| VmError::Value { error, position })?; - self.insert(product, instruction.destination(), position)?; + self.insert(product, instruction.a(), position)?; } Operation::Divide => { let (left, right) = get_arguments(self, instruction, position)?; + + log::debug!("{left} / {right}"); + let quotient = left .divide(right) .map_err(|error| VmError::Value { error, position })?; - self.insert(quotient, instruction.destination(), position)?; + self.insert(quotient, instruction.a(), position)?; } Operation::Modulo => { let (left, right) = get_arguments(self, instruction, position)?; + + log::debug!("{left} % {right}"); + let remainder = left .modulo(right) .map_err(|error| VmError::Value { error, position })?; - self.insert(remainder, instruction.destination(), position)?; + self.insert(remainder, instruction.a(), position)?; } Operation::Test => { - let register = instruction.destination(); - let test_value = instruction.second_argument_as_boolean(); + let register = instruction.a(); + let test_value = instruction.c_as_boolean(); let value = self.get(register, position)?; let boolean = value.as_boolean().ok_or_else(|| VmError::ExpectedBoolean { found: value.clone(), position, })?; - if boolean == test_value { + if boolean != test_value { self.ip += 1; } } Operation::TestSet => { - let to_register = instruction.destination(); - let argument = instruction.first_argument(); - let test_value = instruction.second_argument_as_boolean(); + let to_register = instruction.a(); + let argument = instruction.b(); + let test_value = instruction.c_as_boolean(); let value = self.clone(argument, position)?; let boolean = value.as_boolean().ok_or_else(|| VmError::ExpectedBoolean { found: value.clone(), @@ -235,13 +246,13 @@ impl Vm { found: left.clone(), position, })?; - let compare_to = instruction.destination_as_boolean(); + let compare_to = instruction.a_as_boolean(); if boolean == compare_to { self.ip += 1; } else { - let jump_distance = jump.destination(); - let is_positive = jump.first_argument_as_boolean(); + let jump_distance = jump.a(); + let is_positive = jump.a_as_boolean(); let new_ip = if is_positive { self.ip + jump_distance as usize } else { @@ -265,13 +276,13 @@ impl Vm { found: left.clone(), position, })?; - let compare_to = instruction.destination_as_boolean(); + let compare_to = instruction.a_as_boolean(); if boolean == compare_to { self.ip += 1; } else { - let jump_distance = jump.destination(); - let is_positive = jump.first_argument_as_boolean(); + let jump_distance = jump.a(); + let is_positive = jump.a_as_boolean(); let new_ip = if is_positive { self.ip + jump_distance as usize } else { @@ -295,13 +306,13 @@ impl Vm { found: left.clone(), position, })?; - let compare_to = instruction.destination_as_boolean(); + let compare_to = instruction.a_as_boolean(); if boolean == compare_to { self.ip += 1; } else { - let jump_distance = jump.destination(); - let is_positive = jump.first_argument_as_boolean(); + let jump_distance = jump.a(); + let is_positive = jump.a_as_boolean(); let new_ip = if is_positive { self.ip + jump_distance as usize } else { @@ -312,34 +323,32 @@ impl Vm { } } Operation::Negate => { - let value = if instruction.first_argument_is_constant() { - self.chunk - .get_constant(instruction.first_argument(), position)? + let value = if instruction.b_is_constant() { + self.chunk.get_constant(instruction.b(), position)? } else { - self.get(instruction.first_argument(), position)? + self.get(instruction.b(), position)? }; let negated = value .negate() .map_err(|error| VmError::Value { error, position })?; - self.insert(negated, instruction.destination(), position)?; + self.insert(negated, instruction.a(), position)?; } Operation::Not => { - let value = if instruction.first_argument_is_constant() { - self.chunk - .get_constant(instruction.first_argument(), position)? + let value = if instruction.b_is_constant() { + self.chunk.get_constant(instruction.b(), position)? } else { - self.get(instruction.first_argument(), position)? + self.get(instruction.b(), position)? }; let not = value .not() .map_err(|error| VmError::Value { error, position })?; - self.insert(not, instruction.destination(), position)?; + self.insert(not, instruction.a(), position)?; } Operation::Jump => { - let offset = instruction.first_argument(); - let is_positive = instruction.second_argument_as_boolean(); + let offset = instruction.b(); + let is_positive = instruction.c_as_boolean(); let new_ip = if is_positive { self.ip + offset as usize } else { @@ -349,8 +358,8 @@ impl Vm { self.ip = new_ip; } Operation::Return => { - let start_register = instruction.destination(); - let end_register = instruction.first_argument(); + let start_register = instruction.a(); + let end_register = instruction.b(); let return_value_count = end_register - start_register; if return_value_count == 1 { @@ -358,7 +367,7 @@ impl Vm { } } Operation::End => { - let returns_value = instruction.destination_as_boolean(); + let returns_value = instruction.a_as_boolean(); if returns_value { return Ok(Some(self.pop(position)?)); diff --git a/dust-lang/tests/operations.rs b/dust-lang/tests/expressions.rs similarity index 90% rename from dust-lang/tests/operations.rs rename to dust-lang/tests/expressions.rs index 5f59a00..441a3e2 100644 --- a/dust-lang/tests/operations.rs +++ b/dust-lang/tests/expressions.rs @@ -1,7 +1,16 @@ use dust_lang::*; #[test] -fn if_expression() { +fn if_else() { + assert_eq!(run("if true { 1 } else { 2 }"), Ok(Some(Value::integer(1)))); + assert_eq!( + run("if false { 1 } else { 2 }"), + Ok(Some(Value::integer(2))) + ); +} + +#[test] +fn r#if() { assert_eq!(run("if true { 1 }"), Ok(Some(Value::integer(1)))); assert_eq!( run("if 42 == 42 { 1 } else { 2 }"),