From c5e0d8ef1ed437fc70cca324b55c1efa292b9aab Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 26 Nov 2024 01:15:31 -0500 Subject: [PATCH] Refactor to use 64-bit instructions --- dust-lang/src/chunk.rs | 22 +- dust-lang/src/compiler.rs | 475 ++++++++++++++++---------------- dust-lang/src/disassembler.rs | 7 +- dust-lang/src/instruction.rs | 492 +++++++++++++++++++++++----------- dust-lang/src/lib.rs | 2 +- dust-lang/src/optimizer.rs | 32 +-- dust-lang/src/type.rs | 4 +- dust-lang/src/vm.rs | 26 +- 8 files changed, 620 insertions(+), 440 deletions(-) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 1d76af9..581eb32 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -87,7 +87,7 @@ impl Chunk { &mut self.constants } - pub fn get_constant(&self, index: u8) -> Result<&ConcreteValue, ChunkError> { + pub fn get_constant(&self, index: u16) -> Result<&ConcreteValue, ChunkError> { self.constants .get(index as usize) .ok_or(ChunkError::ConstantIndexOutOfBounds { @@ -95,15 +95,15 @@ impl Chunk { }) } - pub fn push_or_get_constant(&mut self, value: ConcreteValue) -> u8 { + pub fn push_or_get_constant(&mut self, value: ConcreteValue) -> u16 { if let Some(index) = self .constants .iter() .position(|constant| *constant == value) { - index as u8 + index as u16 } else { - let index = self.constants.len() as u8; + let index = self.constants.len() as u16; self.constants.push(value); @@ -133,7 +133,7 @@ impl Chunk { &mut self.locals } - pub fn get_local(&self, index: u8) -> Result<&Local, ChunkError> { + pub fn get_local(&self, index: u16) -> Result<&Local, ChunkError> { self.locals .get(index as usize) .ok_or(ChunkError::LocalIndexOutOfBounds { @@ -141,7 +141,7 @@ impl Chunk { }) } - pub fn get_local_mut(&mut self, index: u8) -> Result<&mut Local, ChunkError> { + pub fn get_local_mut(&mut self, index: u16) -> Result<&mut Local, ChunkError> { self.locals .get_mut(index as usize) .ok_or(ChunkError::LocalIndexOutOfBounds { @@ -149,7 +149,7 @@ impl Chunk { }) } - pub fn get_identifier(&self, local_index: u8) -> Option { + pub fn get_identifier(&self, local_index: u16) -> Option { self.locals.get(local_index as usize).and_then(|local| { self.constants .get(local.identifier_index as usize) @@ -157,7 +157,7 @@ impl Chunk { }) } - pub fn get_constant_type(&self, constant_index: u8) -> Result { + pub fn get_constant_type(&self, constant_index: u16) -> Result { self.constants .get(constant_index as usize) .map(|value| value.r#type()) @@ -166,7 +166,7 @@ impl Chunk { }) } - pub fn get_local_type(&self, local_index: u8) -> Result<&Type, ChunkError> { + pub fn get_local_type(&self, local_index: u16) -> Result<&Type, ChunkError> { self.locals .get(local_index as usize) .map(|local| &local.r#type) @@ -214,7 +214,7 @@ impl PartialEq for Chunk { #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Local { /// The index of the identifier in the constants table. - pub identifier_index: u8, + pub identifier_index: u16, /// The expected type of the local's value. pub r#type: Type, @@ -228,7 +228,7 @@ pub struct Local { impl Local { /// Creates a new Local instance. - pub fn new(identifier_index: u8, r#type: Type, mutable: bool, scope: Scope) -> Self { + pub fn new(identifier_index: u16, r#type: Type, mutable: bool, scope: Scope) -> Self { Self { identifier_index, r#type, diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index f5da9e4..03c2f36 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -48,7 +48,6 @@ pub fn compile(source: &str) -> Result { pub struct Compiler<'src> { chunk: Chunk, lexer: Lexer<'src>, - local_declarations: Vec, current_token: Token<'src>, current_position: Span, @@ -58,7 +57,7 @@ pub struct Compiler<'src> { return_type: Option, optimization_count: usize, previous_expression_type: Type, - minimum_register: u8, + minimum_register: u16, block_index: u8, current_scope: Scope, @@ -78,7 +77,6 @@ impl<'src> Compiler<'src> { Ok(Compiler { chunk, lexer, - local_declarations: Vec::new(), current_token, current_position, previous_token: Token::Eof, @@ -112,7 +110,7 @@ impl<'src> Compiler<'src> { matches!(self.current_token, Token::Eof) } - fn next_register(&self) -> u8 { + fn next_register(&self) -> u16 { self.chunk .instructions() .iter() @@ -146,7 +144,7 @@ impl<'src> Compiler<'src> { Ok(()) } - fn get_local(&self, index: u8) -> Result<&Local, CompileError> { + fn get_local(&self, index: u16) -> Result<&Local, CompileError> { self.chunk .get_local(index) .map_err(|error| CompileError::Chunk { @@ -155,7 +153,7 @@ impl<'src> Compiler<'src> { }) } - fn get_local_index(&self, identifier_text: &str) -> Result { + fn get_local_index(&self, identifier_text: &str) -> Result { self.chunk .locals() .iter() @@ -173,7 +171,7 @@ impl<'src> Compiler<'src> { }; if identifier == identifier_text { - Some(index as u8) + Some(index as u16) } else { None } @@ -190,8 +188,7 @@ impl<'src> Compiler<'src> { r#type: Type, is_mutable: bool, scope: Scope, - register_index: u8, - ) -> (u8, u8) { + ) -> (u16, u16) { log::info!("Declaring local {identifier}"); let identifier = ConcreteValue::string(identifier); @@ -201,34 +198,8 @@ impl<'src> Compiler<'src> { self.chunk .locals_mut() .push(Local::new(identifier_index, r#type, is_mutable, scope)); - self.local_declarations.insert(local_index, register_index); - (local_index as u8, identifier_index) - } - - fn redeclare_local(&mut self, local_index: u8, register_index: u8) -> Result<(), CompileError> { - let local_index = local_index as usize; - - if !self.local_declarations.len() <= local_index { - let local = self.get_local(local_index as u8)?; - let identifier = self - .chunk - .constants() - .get(local.identifier_index as usize) - .map(|constant| constant.to_string()) - .unwrap_or("unknown".to_string()); - - return Err(CompileError::VariableOutOfScope { - identifier, - variable_scope: local.scope, - access_scope: self.current_scope, - position: self.current_position, - }); - } - - self.local_declarations[local_index] = register_index; - - Ok(()) + (local_index as u16, identifier_index) } fn allow(&mut self, allowed: Token) -> Result { @@ -374,7 +345,7 @@ impl<'src> Compiler<'src> { } } - pub fn get_register_type(&self, register_index: u8) -> Result { + pub fn get_register_type(&self, register_index: u16) -> Result { for (index, (instruction, _)) in self.chunk.instructions().iter().enumerate() { if instruction.a() == register_index { if let Operation::LoadList = instruction.operation() { @@ -459,11 +430,13 @@ impl<'src> Compiler<'src> { ) -> Result<(), CompileError> { let constant_index = self.chunk.push_or_get_constant(constant); let register = self.next_register(); + let instruction = Instruction::builder(Operation::LoadConstant) + .a(register) + .b(constant_index) + .c_to_boolean(false) + .build(); - self.emit_instruction( - Instruction::load_constant(register, constant_index, false), - position, - ); + self.emit_instruction(instruction, position); Ok(()) } @@ -476,11 +449,13 @@ impl<'src> Compiler<'src> { let boolean = text.parse::().unwrap(); let register = self.next_register(); + let instruction = Instruction::builder(Operation::LoadBoolean) + .a(register) + .b_to_boolean(boolean) + .c_to_boolean(false) + .build(); - self.emit_instruction( - Instruction::load_boolean(register, boolean, false), - position, - ); + self.emit_instruction(instruction, position); self.previous_expression_type = Type::Boolean; @@ -656,9 +631,17 @@ impl<'src> Compiler<'src> { } let register = self.next_register(); - let mut instruction = match operator.kind() { - TokenKind::Bang => Instruction::not(register, argument), - TokenKind::Minus => Instruction::negate(register, argument), + let instruction = match operator.kind() { + TokenKind::Bang => Instruction::builder(Operation::Not) + .a(register) + .b(argument) + .b_is_constant(is_constant) + .build(), + TokenKind::Minus => Instruction::builder(Operation::Negate) + .a(register) + .b(argument) + .b_is_constant(is_constant) + .build(), _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[TokenKind::Bang, TokenKind::Minus], @@ -668,10 +651,6 @@ impl<'src> Compiler<'src> { } }; - if is_constant { - instruction.set_b_is_constant(); - } - self.emit_instruction(instruction, operator_position); if let TokenKind::Bang = operator.kind() { @@ -684,32 +663,19 @@ impl<'src> Compiler<'src> { fn handle_binary_argument( &mut self, instruction: &Instruction, - ) -> Result<(bool, bool, bool, u8), CompileError> { + ) -> Result<(bool, bool, bool, bool, u16), CompileError> { let mut push_back = false; let mut is_constant = false; + let mut is_local = false; let mut is_mutable_local = false; let argument = match instruction.operation() { Operation::GetLocal => { let local_index = instruction.b(); let local = self.get_local(local_index)?; + is_local = true; is_mutable_local = local.is_mutable; - *self - .local_declarations - .get(local_index as usize) - .ok_or_else(|| { - let identifier = self - .chunk - .constants() - .get(local.identifier_index as usize) - .unwrap() - .to_string(); - - CompileError::UndeclaredVariable { - identifier, - position: self.current_position, - } - })? + local_index } Operation::LoadConstant => { is_constant = true; @@ -733,7 +699,7 @@ impl<'src> Compiler<'src> { } }; - Ok((push_back, is_constant, is_mutable_local, argument)) + Ok((push_back, is_constant, is_local, is_mutable_local, argument)) } fn parse_math_binary(&mut self) -> Result<(), CompileError> { @@ -744,7 +710,7 @@ impl<'src> Compiler<'src> { position: self.previous_position, } })?; - let (push_back_left, left_is_constant, left_is_mutable_local, left) = + let (push_back_left, left_is_constant, left_is_local, left_is_mutable_local, left) = self.handle_binary_argument(&left_instruction)?; if push_back_left { @@ -774,7 +740,7 @@ impl<'src> Compiler<'src> { self.parse_sub_expression(&rule.precedence)?; let (right_instruction, right_position) = self.pop_last_instruction()?; - let (push_back_right, right_is_constant, _, right) = + let (push_back_right, right_is_constant, right_is_local, _, right) = self.handle_binary_argument(&right_instruction)?; if push_back_right { @@ -786,17 +752,17 @@ impl<'src> Compiler<'src> { } else { self.next_register() }; - let mut new_instruction = match operator { - Token::Plus => Instruction::add(register, left, right), - Token::PlusEqual => Instruction::add(register, left, right), - Token::Minus => Instruction::subtract(register, left, right), - Token::MinusEqual => Instruction::subtract(register, left, right), - Token::Star => Instruction::multiply(register, left, right), - Token::StarEqual => Instruction::multiply(register, left, right), - Token::Slash => Instruction::divide(register, left, right), - Token::SlashEqual => Instruction::divide(register, left, right), - Token::Percent => Instruction::modulo(register, left, right), - Token::PercentEqual => Instruction::modulo(register, left, right), + let operation = match operator { + Token::Plus => Operation::Add, + Token::PlusEqual => Operation::Add, + Token::Minus => Operation::Subtract, + Token::MinusEqual => Operation::Subtract, + Token::Star => Operation::Multiply, + Token::StarEqual => Operation::Multiply, + Token::Slash => Operation::Divide, + Token::SlashEqual => Operation::Divide, + Token::Percent => Operation::Modulo, + Token::PercentEqual => Operation::Modulo, _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[ @@ -817,15 +783,15 @@ impl<'src> Compiler<'src> { } }; - if left_is_constant { - new_instruction.set_b_is_constant(); - } + let instruction = Instruction::builder(operation) + .a(register) + .b(left) + .c(right) + .b_is_constant(left_is_constant) + .c_is_constant(right_is_constant) + .build(); - if right_is_constant { - new_instruction.set_c_is_constant(); - } - - self.emit_instruction(new_instruction, operator_position); + self.emit_instruction(instruction, operator_position); if is_assignment { self.previous_expression_type = Type::None; @@ -852,7 +818,7 @@ impl<'src> Compiler<'src> { position: self.previous_position, } })?; - let (push_back_left, left_is_constant, _, left) = + let (push_back_left, left_is_constant, left_is_local, _, left) = self.handle_binary_argument(&left_instruction)?; let operator = self.current_token; let operator_position = self.current_position; @@ -868,16 +834,15 @@ impl<'src> Compiler<'src> { position: self.previous_position, } })?; - let (push_back_right, right_is_constant, _, right) = + let (push_back_right, right_is_constant, right_is_local, _, right) = self.handle_binary_argument(&right_instruction)?; - - let mut instruction = match operator { - Token::DoubleEqual => Instruction::equal(true, left, right), - Token::BangEqual => Instruction::equal(false, left, right), - Token::Less => Instruction::less(true, left, right), - Token::LessEqual => Instruction::less_equal(true, left, right), - Token::Greater => Instruction::less_equal(false, left, right), - Token::GreaterEqual => Instruction::less(false, left, right), + let (operation, instruction_boolean) = match operator { + Token::DoubleEqual => (Operation::Equal, true), + Token::BangEqual => (Operation::Equal, false), + Token::Less => (Operation::Less, true), + Token::LessEqual => (Operation::LessEqual, true), + Token::Greater => (Operation::LessEqual, false), + Token::GreaterEqual => (Operation::Less, false), _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[ @@ -893,14 +858,13 @@ impl<'src> Compiler<'src> { }) } }; - - if left_is_constant { - instruction.set_b_is_constant(); - } - - if right_is_constant { - instruction.set_c_is_constant(); - } + let instruction = Instruction::builder(operation) + .a_to_boolean(instruction_boolean) + .b(left) + .c(right) + .b_is_constant(left_is_constant) + .c_is_constant(right_is_constant) + .build(); if push_back_left { self.emit_instruction(left_instruction, left_position); @@ -911,17 +875,25 @@ impl<'src> Compiler<'src> { } let register = self.next_register(); + let jump = Instruction::builder(Operation::Jump) + .a(1) + .b_to_boolean(true) + .build(); + let load_true = Instruction::builder(Operation::LoadBoolean) + .a(register) + .b_to_boolean(true) + .c_to_boolean(true) + .build(); + let load_false = Instruction::builder(Operation::LoadBoolean) + .a(register) + .b_to_boolean(false) + .c_to_boolean(false) + .build(); self.emit_instruction(instruction, operator_position); - self.emit_instruction(Instruction::jump(1, true), operator_position); - self.emit_instruction( - Instruction::load_boolean(register, true, true), - operator_position, - ); - self.emit_instruction( - Instruction::load_boolean(register, false, false), - operator_position, - ); + self.emit_instruction(jump, operator_position); + self.emit_instruction(load_true, operator_position); + self.emit_instruction(load_false, operator_position); self.previous_expression_type = Type::Boolean; @@ -938,14 +910,14 @@ impl<'src> Compiler<'src> { }); } - let (_, is_constant, _, _) = self.handle_binary_argument(&left_instruction)?; + let (_, is_constant, is_local, _, _) = self.handle_binary_argument(&left_instruction)?; let operator = self.current_token; let operator_position = self.current_position; let rule = ParseRule::from(&operator); let test_register = left_instruction.a(); - let mut test_instruction = match operator { - Token::DoubleAmpersand => Instruction::test(test_register, true), - Token::DoublePipe => Instruction::test(test_register, false), + let test_boolean = match operator { + Token::DoubleAmpersand => true, + Token::DoublePipe => false, _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[TokenKind::DoubleAmpersand, TokenKind::DoublePipe], @@ -954,15 +926,19 @@ impl<'src> Compiler<'src> { }) } }; - - if is_constant { - test_instruction.set_b_is_constant(); - } + let test = Instruction::builder(Operation::Test) + .b(test_register) + .c_to_boolean(test_boolean) + .build(); + let jump = Instruction::builder(Operation::Jump) + .a(1) + .b_to_boolean(true) + .build(); self.advance()?; self.emit_instruction(left_instruction, left_position); - self.emit_instruction(test_instruction, operator_position); - self.emit_instruction(Instruction::jump(1, true), operator_position); + self.emit_instruction(test, operator_position); + self.emit_instruction(jump, operator_position); self.parse_sub_expression(&rule.precedence)?; self.previous_expression_type = Type::Boolean; @@ -989,8 +965,11 @@ impl<'src> Compiler<'src> { return self.parse_native_call(native_function); } else if Some(identifier) == self.chunk.name().map(|string| string.as_str()) { let register = self.next_register(); + let load_self = Instruction::builder(Operation::LoadSelf) + .a(register) + .build(); - self.emit_instruction(Instruction::load_self(register), start_position); + self.emit_instruction(load_self, start_position); self.previous_expression_type = Type::SelfChunk; @@ -1024,13 +1003,13 @@ impl<'src> Compiler<'src> { self.parse_expression()?; - let register = self.local_declarations[local_index as usize]; + let register = self.next_register(); + let set_local = Instruction::builder(Operation::SetLocal) + .a(register) + .b(local_index) + .build(); - self.redeclare_local(local_index, register)?; - self.emit_instruction( - Instruction::set_local(register, local_index), - start_position, - ); + self.emit_instruction(set_local, start_position); self.previous_expression_type = Type::None; @@ -1045,11 +1024,12 @@ impl<'src> Compiler<'src> { } let register = self.next_register(); + let get_local = Instruction::builder(Operation::GetLocal) + .a(register) + .b(local_index) + .build(); - self.emit_instruction( - Instruction::get_local(register, local_index), - self.previous_position, - ); + self.emit_instruction(get_local, self.previous_position); let local = self.get_local(local_index)?; @@ -1118,12 +1098,13 @@ impl<'src> Compiler<'src> { item_type = self.previous_expression_type.clone(); let actual_register = self.next_register() - 1; + let close = Instruction::builder(Operation::Close) + .a(expected_register) + .b(actual_register) + .build(); if expected_register < actual_register { - self.emit_instruction( - Instruction::close(expected_register, actual_register), - self.current_position, - ); + self.emit_instruction(close, self.current_position); } self.allow(Token::Comma)?; @@ -1131,11 +1112,12 @@ impl<'src> Compiler<'src> { let to_register = self.next_register(); let end = self.current_position.1; + let load_list = Instruction::builder(Operation::LoadList) + .a(to_register) + .b(start_register) + .build(); - self.emit_instruction( - Instruction::load_list(to_register, start_register), - Span(start, end), - ); + self.emit_instruction(load_list, Span(start, end)); self.previous_expression_type = Type::List { item_type: Box::new(item_type), @@ -1163,11 +1145,12 @@ impl<'src> Compiler<'src> { self.chunk.instructions_mut().pop(); } else if let Some((instruction, _)) = self.chunk.instructions().last() { let test_register = instruction.a(); + let test = Instruction::builder(Operation::Test) + .b(test_register) + .c_to_boolean(true) + .build(); - self.emit_instruction( - Instruction::test(test_register, true), - self.current_position, - ) + self.emit_instruction(test, self.current_position) } let if_block_start = self.chunk.len(); @@ -1184,7 +1167,7 @@ impl<'src> Compiler<'src> { } let if_block_end = self.chunk.len(); - let mut if_block_distance = (if_block_end - if_block_start) as u8; + let mut if_block_distance = (if_block_end - if_block_start) as u16; let if_block_type = self.previous_expression_type.clone(); let if_last_register = self.next_register().saturating_sub(1); @@ -1211,7 +1194,7 @@ impl<'src> Compiler<'src> { }; let else_block_end = self.chunk.len(); - let else_block_distance = (else_block_end - if_block_end) as u8; + let else_block_distance = (else_block_end - if_block_end) as u16; if let Err(conflict) = if_block_type.check(&self.previous_expression_type) { return Err(CompileError::IfElseBranchMismatch { @@ -1229,36 +1212,37 @@ impl<'src> Compiler<'src> { skippable.set_c_to_boolean(true); } else { if_block_distance += 1; + let jump = Instruction::builder(Operation::Jump) + .b(else_block_distance) + .c_to_boolean(true) + .build(); - self.chunk.instructions_mut().insert( - if_block_end, - ( - Instruction::jump(else_block_distance, true), - self.current_position, - ), - ); + self.chunk + .instructions_mut() + .insert(if_block_end, (jump, self.current_position)); } } 2.. => { if_block_distance += 1; + let jump = Instruction::builder(Operation::Jump) + .b(else_block_distance) + .c_to_boolean(true) + .build(); - self.chunk.instructions_mut().insert( - if_block_end, - ( - Instruction::jump(else_block_distance, true), - self.current_position, - ), - ); + self.chunk + .instructions_mut() + .insert(if_block_end, (jump, self.current_position)); } } - self.chunk.instructions_mut().insert( - if_block_start, - ( - Instruction::jump(if_block_distance, true), - if_block_start_position, - ), - ); + let jump = Instruction::builder(Operation::Jump) + .b(if_block_distance) + .c_to_boolean(true) + .build(); + + self.chunk + .instructions_mut() + .insert(if_block_start, (jump, if_block_start_position)); if self.chunk.len() >= 4 { let mut optimizer = Optimizer::new(&mut self.chunk); @@ -1269,12 +1253,13 @@ impl<'src> Compiler<'src> { } let else_last_register = self.next_register().saturating_sub(1); + let r#move = Instruction::builder(Operation::Move) + .a(if_last_register) + .b(else_last_register) + .build(); if if_last_register < else_last_register { - self.emit_instruction( - Instruction::r#move(else_last_register, if_last_register), - self.current_position, - ); + self.emit_instruction(r#move, self.current_position); } Ok(()) @@ -1283,7 +1268,7 @@ impl<'src> Compiler<'src> { fn parse_while(&mut self) -> Result<(), CompileError> { self.advance()?; - let expression_start = self.chunk.len() as u8; + let expression_start = self.chunk.len() as u16; self.parse_expression()?; @@ -1305,18 +1290,22 @@ impl<'src> Compiler<'src> { self.parse_block()?; - let block_end = self.chunk.len() as u8; + let block_end = self.chunk.len() as u16; + let jump_distance = block_end - block_start as u16 + 1; + let jump = Instruction::builder(Operation::Jump) + .b(jump_distance) + .c_to_boolean(true) + .build(); - self.chunk.instructions_mut().insert( - block_start, - ( - Instruction::jump(block_end - block_start as u8 + 1, true), - self.current_position, - ), - ); + self.chunk + .instructions_mut() + .insert(block_start, (jump, self.current_position)); let jump_back_distance = block_end - expression_start + 1; - let jump_back = Instruction::jump(jump_back_distance, false); + let jump_back = Instruction::builder(Operation::Jump) + .b(jump_back_distance) + .c_to_boolean(false) + .build(); self.emit_instruction(jump_back, self.current_position); @@ -1339,25 +1328,29 @@ impl<'src> Compiler<'src> { let actual_register = self.next_register() - 1; if expected_register < actual_register { - self.emit_instruction( - Instruction::close(expected_register, actual_register), - self.current_position, - ); + let close = Instruction::builder(Operation::Close) + .b(expected_register) + .c(actual_register) + .build(); + + self.emit_instruction(close, self.current_position); } self.allow(Token::Comma)?; } + self.previous_expression_type = *function.r#type().return_type; let end = self.previous_position.1; let to_register = self.next_register(); let argument_count = to_register - start_register; + let call_native = Instruction::builder(Operation::CallNative) + .a(start_register) + .b(function as u16) + .c(argument_count) + .build(); - self.previous_expression_type = *function.r#type().return_type; + self.emit_instruction(call_native, Span(start, end)); - self.emit_instruction( - Instruction::call_native(to_register, function, argument_count), - Span(start, end), - ); Ok(()) } @@ -1409,8 +1402,11 @@ impl<'src> Compiler<'src> { true }; let end = self.current_position.1; + let r#return = Instruction::builder(Operation::Return) + .b_to_boolean(has_return_value) + .build(); - self.emit_instruction(Instruction::r#return(has_return_value), Span(start, end)); + self.emit_instruction(r#return, Span(start, end)); self.previous_expression_type = Type::None; @@ -1419,12 +1415,18 @@ impl<'src> Compiler<'src> { fn parse_implicit_return(&mut self) -> Result<(), CompileError> { if self.allow(Token::Semicolon)? { - self.emit_instruction(Instruction::r#return(false), self.current_position); + let r#return = Instruction::builder(Operation::Return) + .b_to_boolean(false) + .build(); + + self.emit_instruction(r#return, self.current_position); } else { - self.emit_instruction( - Instruction::r#return(self.previous_expression_type != Type::None), - self.current_position, - ); + let should_return_value = self.previous_expression_type != Type::None; + let r#return = Instruction::builder(Operation::Return) + .b_to_boolean(should_return_value) + .build(); + + self.emit_instruction(r#return, self.current_position); } Ok(()) @@ -1466,12 +1468,14 @@ impl<'src> Compiler<'src> { self.get_register_type(register)? }; let (local_index, _) = - self.declare_local(identifier, r#type, is_mutable, self.current_scope, register); + self.declare_local(identifier, r#type, is_mutable, self.current_scope); + let define_local = Instruction::builder(Operation::DefineLocal) + .a(register) + .b(local_index) + .c_to_boolean(is_mutable) + .build(); - self.emit_instruction( - Instruction::define_local(register, local_index, is_mutable), - position, - ); + self.emit_instruction(define_local, position); self.previous_expression_type = Type::None; @@ -1494,7 +1498,7 @@ impl<'src> Compiler<'src> { function_compiler.expect(Token::LeftParenthesis)?; - let mut value_parameters: Option> = None; + let mut value_parameters: Option> = None; while function_compiler.current_token != Token::RightParenthesis { let is_mutable = function_compiler.allow(Token::Mut)?; @@ -1519,13 +1523,11 @@ impl<'src> Compiler<'src> { function_compiler.advance()?; - let register = function_compiler.next_register(); let (_, identifier_index) = function_compiler.declare_local( parameter, r#type.clone(), is_mutable, function_compiler.current_scope, - register, ); if let Some(value_parameters) = value_parameters.as_mut() { @@ -1582,24 +1584,30 @@ impl<'src> Compiler<'src> { Type::Function(function_type), false, self.current_scope, - register, ); + let load_constant = Instruction::builder(Operation::LoadConstant) + .a(register) + .b(constant_index) + .c_to_boolean(false) + .build(); + let define_local = Instruction::builder(Operation::DefineLocal) + .a(register) + .b(local_index) + .c_to_boolean(false) + .build(); - self.emit_instruction( - Instruction::load_constant(register, constant_index, false), - Span(function_start, function_end), - ); - self.emit_instruction( - Instruction::define_local(register, local_index, false), - position, - ); + self.emit_instruction(load_constant, Span(function_start, function_end)); + self.emit_instruction(define_local, position); self.previous_expression_type = Type::None; } else { - self.emit_instruction( - Instruction::load_constant(register, constant_index, false), - Span(function_start, function_end), - ); + let load_constant = Instruction::builder(Operation::LoadConstant) + .a(register) + .b(constant_index) + .c_to_boolean(false) + .build(); + + self.emit_instruction(load_constant, Span(function_start, function_end)); self.previous_expression_type = Type::Function(function_type); } @@ -1647,12 +1655,13 @@ impl<'src> Compiler<'src> { self.parse_expression()?; let actual_register = self.next_register() - 1; + let close = Instruction::builder(Operation::Close) + .b(expected_register) + .c(actual_register) + .build(); if expected_register < actual_register { - self.emit_instruction( - Instruction::close(expected_register, actual_register), - self.current_position, - ); + self.emit_instruction(close, self.current_position); } self.allow(Token::Comma)?; @@ -1661,11 +1670,13 @@ impl<'src> Compiler<'src> { let end = self.current_position.1; let to_register = self.next_register(); let argument_count = to_register - function_register - 1; + let call = Instruction::builder(Operation::Call) + .a(to_register) + .b(function_register) + .c(argument_count) + .build(); - self.emit_instruction( - Instruction::call(to_register, function_register, argument_count), - Span(start, end), - ); + self.emit_instruction(call, Span(start, end)); self.previous_expression_type = function_return_type; diff --git a/dust-lang/src/disassembler.rs b/dust-lang/src/disassembler.rs index 238a202..61c4368 100644 --- a/dust-lang/src/disassembler.rs +++ b/dust-lang/src/disassembler.rs @@ -50,8 +50,8 @@ use crate::{value::ConcreteValue, Chunk, Local}; const INSTRUCTION_HEADER: [&str; 4] = [ "Instructions", "------------", - " i POSITION BYTECODE OPERATION INFO ", - "--- ---------- -------- ------------- ------------------------------------", + " i POSITION OPERATION INFO ", + "--- ---------- ------------- ------------------------------------", ]; const CONSTANT_HEADER: [&str; 4] = [ @@ -257,12 +257,11 @@ impl<'a> Disassembler<'a> { for (index, (instruction, position)) in self.chunk.instructions().iter().enumerate() { let position = position.to_string(); - let bytecode = format!("{:02X}", u32::from(instruction)); let operation = instruction.operation().to_string(); let info = instruction.disassembly_info(self.chunk); let instruction_display = - format!("{index:^3} {position:^10} {bytecode:>8} {operation:13} {info:^36}"); + format!("{index:^3} {position:^10} {operation:13} {info:^36}"); self.push_details(&instruction_display); } diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index eba0f94..c336e51 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -46,57 +46,110 @@ impl InstructionBuilder { ) } - pub fn set_a(&mut self, a: u16) -> &mut Self { + pub fn a(&mut self, a: u16) -> &mut Self { self.a = a; self } - pub fn set_b(&mut self, b: u16) -> &mut Self { + pub fn a_to_boolean(&mut self, a: bool) -> &mut Self { + self.a = a as u16; + self + } + + pub fn b(&mut self, b: u16) -> &mut Self { self.b = b; self } - pub fn set_b_to_boolean(&mut self, b: bool) -> &mut Self { + pub fn b_to_boolean(&mut self, b: bool) -> &mut Self { self.b = b as u16; self } - pub fn set_c(&mut self, c: u16) -> &mut Self { + pub fn c(&mut self, c: u16) -> &mut Self { self.c = c; self } - pub fn set_c_to_boolean(&mut self, c: bool) -> &mut Self { + pub fn c_to_boolean(&mut self, c: bool) -> &mut Self { self.c = c as u16; self } - pub fn set_b_is_constant(&mut self, b_is_constant: bool) -> &mut Self { + pub fn b_is_constant(&mut self, b_is_constant: bool) -> &mut Self { self.b_is_constant = b_is_constant; self } - pub fn set_c_is_constant(&mut self, c_is_constant: bool) -> &mut Self { + pub fn c_is_constant(&mut self, c_is_constant: bool) -> &mut Self { self.c_is_constant = c_is_constant; self } - pub fn set_a_is_local(&mut self, a_is_local: bool) -> &mut Self { + pub fn a_is_local(&mut self, a_is_local: bool) -> &mut Self { self.a_is_local = a_is_local; self } - pub fn set_b_is_local(&mut self, b_is_local: bool) -> &mut Self { + pub fn b_is_local(&mut self, b_is_local: bool) -> &mut Self { self.b_is_local = b_is_local; self } - pub fn set_c_is_local(&mut self, c_is_local: bool) -> &mut Self { + pub fn c_is_local(&mut self, c_is_local: bool) -> &mut Self { self.c_is_local = c_is_local; self } } +impl From<&Instruction> for InstructionBuilder { + fn from(instruction: &Instruction) -> Self { + InstructionBuilder { + operation: instruction.operation(), + a: instruction.a(), + b: instruction.b(), + c: instruction.c(), + b_is_constant: instruction.b_is_constant(), + c_is_constant: instruction.c_is_constant(), + a_is_local: instruction.a_is_local(), + b_is_local: instruction.b_is_local(), + c_is_local: instruction.c_is_local(), + } + } +} + +impl From for InstructionBuilder { + fn from(instruction: Instruction) -> Self { + InstructionBuilder { + operation: instruction.operation(), + a: instruction.a(), + b: instruction.b(), + c: instruction.c(), + b_is_constant: instruction.b_is_constant(), + c_is_constant: instruction.c_is_constant(), + a_is_local: instruction.a_is_local(), + b_is_local: instruction.b_is_local(), + c_is_local: instruction.c_is_local(), + } + } +} + +impl From<&mut Instruction> for InstructionBuilder { + fn from(instruction: &mut Instruction) -> Self { + InstructionBuilder { + operation: instruction.operation(), + a: instruction.a(), + b: instruction.b(), + c: instruction.c(), + b_is_constant: instruction.b_is_constant(), + c_is_constant: instruction.c_is_constant(), + a_is_local: instruction.a_is_local(), + b_is_local: instruction.b_is_local(), + c_is_local: instruction.c_is_local(), + } + } +} + /// An operation and its arguments for the Dust virtual machine. /// /// See the [module-level documentation](index.html) for more information. @@ -104,6 +157,10 @@ impl InstructionBuilder { pub struct Instruction(u64); impl Instruction { + pub fn new(operation: Operation) -> Instruction { + Instruction(operation as u64) + } + pub fn builder(operation: Operation) -> InstructionBuilder { InstructionBuilder { operation, @@ -118,195 +175,267 @@ impl Instruction { } } + pub fn operation(&self) -> Operation { + Operation::from((self.0 & 0b11111111) as u8) + } + + pub fn set_b_is_constant(&mut self) -> &mut Self { + self.0 = (self.0 & !(1 << 9)) | ((true as u64) << 9); + + self + } + + pub fn set_c_is_constant(&mut self) -> &mut Self { + self.0 = (self.0 & !(1 << 10)) | ((true as u64) << 10); + + self + } + + pub fn set_a_is_local(&mut self) -> &mut Self { + self.0 = (self.0 & !(1 << 11)) | ((true as u64) << 11); + + self + } + + pub fn set_b_is_local(&mut self) -> &mut Self { + self.0 = (self.0 & !(1 << 12)) | ((true as u64) << 12); + + self + } + + pub fn set_c_is_local(&mut self) -> &mut Self { + self.0 = (self.0 & !(1 << 13)) | ((true as u64) << 13); + + self + } + + pub fn a(&self) -> u16 { + ((self.0 >> 16) & 0b1111111111111111) as u16 + } + + pub fn a_as_boolean(&self) -> bool { + self.a() != 0 + } + + pub fn set_a(&mut self, a: u16) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 16)) | ((a as u64) << 16); + + self + } + + pub fn set_a_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 16)) | ((boolean as u64) << 16); + + self + } + + pub fn b(&self) -> u16 { + ((self.0 >> 32) & 0b1111111111111111) as u16 + } + + pub fn b_as_boolean(&self) -> bool { + self.b() != 0 + } + + pub fn set_b(&mut self, b: u16) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 32)) | ((b as u64) << 32); + + self + } + + pub fn set_b_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 32)) | ((boolean as u64) << 32); + + self + } + + pub fn c(&self) -> u16 { + ((self.0 >> 48) & 0b1111111111111111) as u16 + } + + pub fn c_as_boolean(&self) -> bool { + self.c() != 0 + } + + pub fn set_c(&mut self, c: u16) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 48)) | ((c as u64) << 48); + + self + } + + pub fn set_c_to_boolean(&mut self, boolean: bool) -> &mut Self { + self.0 = (self.0 & !(0b1111111111111111 << 48)) | ((boolean as u64) << 48); + + self + } + + pub fn b_is_constant(&self) -> bool { + (self.0 >> 9) & 1 == 1 + } + + pub fn c_is_constant(&self) -> bool { + (self.0 >> 10) & 1 == 1 + } + + pub fn a_is_local(&self) -> bool { + (self.0 >> 11) & 1 == 1 + } + + pub fn b_is_local(&self) -> bool { + (self.0 >> 12) & 1 == 1 + } + + pub fn c_is_local(&self) -> bool { + (self.0 >> 13) & 1 == 1 + } + pub fn r#move(to_register: u16, from_register: u16) -> Instruction { - Instruction::builder(Operation::Move) - .set_a(to_register) - .set_b(from_register) - .build() + *Instruction::new(Operation::Move) + .set_b(to_register) + .set_c(from_register) } pub fn close(from_register: u16, to_register: u16) -> Instruction { - Instruction::builder(Operation::Close) + *Instruction::new(Operation::Close) .set_b(from_register) .set_c(to_register) - .build() } pub fn load_boolean(to_register: u16, value: bool, skip: bool) -> Instruction { - Instruction::builder(Operation::LoadBoolean) + *Instruction::new(Operation::LoadBoolean) .set_a(to_register) .set_b_to_boolean(value) .set_c_to_boolean(skip) - .build() } pub fn load_constant(to_register: u16, constant_index: u16, skip: bool) -> Instruction { - Instruction::builder(Operation::LoadConstant) + *Instruction::new(Operation::LoadConstant) .set_a(to_register) .set_b(constant_index) .set_c_to_boolean(skip) - .build() } pub fn load_list(to_register: u16, start_register: u16) -> Instruction { - Instruction::builder(Operation::LoadList) + *Instruction::new(Operation::LoadList) .set_a(to_register) .set_b(start_register) - .build() } pub fn load_self(to_register: u16) -> Instruction { - Instruction::builder(Operation::LoadSelf) - .set_a(to_register) - .build() + *Instruction::new(Operation::LoadSelf).set_a(to_register) } pub fn define_local(to_register: u16, local_index: u16, is_mutable: bool) -> Instruction { - Instruction::builder(Operation::DefineLocal) - .set_a(to_register as u16) - .set_b(local_index as u16) + *Instruction::new(Operation::DefineLocal) + .set_a(to_register) + .set_b(local_index) .set_c_to_boolean(is_mutable) - .build() } pub fn get_local(to_register: u16, local_index: u16) -> Instruction { - Instruction::builder(Operation::GetLocal) + *Instruction::new(Operation::GetLocal) .set_a(to_register) .set_b(local_index) - .build() } pub fn set_local(from_register: u16, local_index: u16) -> Instruction { - Instruction::builder(Operation::SetLocal) + *Instruction::new(Operation::SetLocal) .set_a(from_register) .set_b(local_index) - .build() } - // pub fn add(to_register: u16, left_index: u16, right_index: u16) -> Instruction { - // Instruction::builder(Operation::Add) - // .set_a(to_register) - // .set_b(left_index) - // .set_c(right_index) - // .build() - // } + pub fn add(to_register: u16, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Add) + .set_a(to_register) + .set_b(left_index) + .set_c(right_index) + } - // pub fn subtract(to_register: u16, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Subtract as u32); + pub fn subtract(to_register: u16, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Subtract) + .set_a(to_register) + .set_b(left_index) + .set_c(right_index) + } - // instruction.set_a(to_register); - // instruction.set_b(left_index); - // instruction.set_c(right_index); + pub fn multiply(to_register: u16, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Multiply) + .set_a(to_register) + .set_b(left_index) + .set_c(right_index) + } - // instruction - // } + pub fn divide(to_register: u16, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Divide) + .set_a(to_register) + .set_b(left_index) + .set_c(right_index) + } - // pub fn multiply(to_register: u16, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Multiply as u32); + pub fn modulo(to_register: u16, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Modulo) + .set_a(to_register) + .set_b(left_index) + .set_c(right_index) + } - // instruction.set_a(to_register); - // instruction.set_b(left_index); - // instruction.set_c(right_index); + pub fn test(test_register: u16, test_value: bool) -> Instruction { + *Instruction::new(Operation::Test) + .set_b(test_register) + .set_c_to_boolean(test_value) + } - // instruction - // } + pub fn test_set(to_register: u16, argument_index: u16, test_value: bool) -> Instruction { + *Instruction::new(Operation::TestSet) + .set_a(to_register) + .set_b(argument_index) + .set_c_to_boolean(test_value) + } - // pub fn divide(to_register: u16, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Divide as u32); + pub fn equal(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Equal) + .set_a_to_boolean(comparison_boolean) + .set_b(left_index) + .set_c(right_index) + } - // instruction.set_a(to_register); - // instruction.set_b(left_index); - // instruction.set_c(right_index); + pub fn less(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::Less) + .set_a_to_boolean(comparison_boolean) + .set_b(left_index) + .set_c(right_index) + } - // instruction - // } + pub fn less_equal(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { + *Instruction::new(Operation::LessEqual) + .set_a_to_boolean(comparison_boolean) + .set_b(left_index) + .set_c(right_index) + } - // pub fn modulo(to_register: u16, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Modulo as u32); + pub fn negate(to_register: u16, from_index: u16) -> Instruction { + *Instruction::new(Operation::Negate) + .set_a(to_register) + .set_b(from_index) + } - // instruction.set_a(to_register); - // instruction.set_b(left_index); - // instruction.set_c(right_index); - - // instruction - // } - - // pub fn test(test_register: u16, test_value: bool) -> Instruction { - // Instruction::builder(Operation::Test) - // .set_b(test_register) - // .set_c_to_boolean(test_value) - // .build() - // } - - // pub fn test_set(to_register: u16, argument_index: u16, test_value: bool) -> Instruction { - // Instruction::builder(Operation::TestSet) - // .set_a(to_register) - // .set_b(argument_index) - // .set_c_to_boolean(test_value) - // .build() - // } - - // pub fn equal(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Equal as u32); - - // instruction.set_a_to_boolean(comparison_boolean); - // instruction.set_b(left_index); - // instruction.set_c(right_index); - - // instruction - // } - - // pub fn less(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Less as u32); - - // instruction.set_a_to_boolean(comparison_boolean); - // instruction.set_b(left_index); - // instruction.set_c(right_index); - - // instruction - // } - - // pub fn less_equal(comparison_boolean: bool, left_index: u16, right_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::LessEqual as u32); - - // instruction.set_a_to_boolean(comparison_boolean); - // instruction.set_b(left_index); - // instruction.set_c(right_index); - - // instruction - // } - - // pub fn negate(to_register: u16, from_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Negate as u32); - - // instruction.set_a(to_register); - // instruction.set_b(from_index); - - // instruction - // } - - // pub fn not(to_register: u16, from_index: u16) -> Instruction { - // let mut instruction = Instruction(Operation::Not as u32); - - // instruction.set_a(to_register); - // instruction.set_b(from_index); - - // instruction - // } + pub fn not(to_register: u16, from_index: u16) -> Instruction { + *Instruction::new(Operation::Not) + .set_a(to_register) + .set_b(from_index) + } pub fn jump(jump_offset: u16, is_positive: bool) -> Instruction { - Instruction::builder(Operation::Jump) + *Instruction::new(Operation::Jump) .set_b(jump_offset) .set_c_to_boolean(is_positive) - .build() } pub fn call(to_register: u16, function_register: u16, argument_count: u16) -> Instruction { - Instruction::builder(Operation::Call) + *Instruction::new(Operation::Call) .set_a(to_register) .set_b(function_register) .set_c(argument_count) - .build() } pub fn call_native( @@ -314,17 +443,49 @@ impl Instruction { native_fn: NativeFunction, argument_count: u16, ) -> Instruction { - Instruction::builder(Operation::CallNative) + *Instruction::new(Operation::CallNative) .set_a(to_register) .set_b(native_fn as u16) .set_c(argument_count) - .build() } pub fn r#return(should_return_value: bool) -> Instruction { - Instruction::builder(Operation::Return) - .set_b_to_boolean(should_return_value) - .build() + *Instruction::new(Operation::Return).set_b_to_boolean(should_return_value) + } + pub fn yields_value(&self) -> bool { + match self.operation() { + Operation::LoadBoolean + | Operation::LoadConstant + | Operation::LoadList + | Operation::LoadSelf + | Operation::GetLocal + | Operation::Add + | Operation::Subtract + | Operation::Multiply + | Operation::Divide + | Operation::Modulo + | Operation::Equal + | Operation::Less + | Operation::LessEqual + | Operation::Negate + | Operation::Not + | Operation::Call => true, + + Operation::CallNative => { + let function = NativeFunction::from(self.b()); + + function.returns_value() + } + + Operation::Move + | Operation::Close + | Operation::DefineLocal + | Operation::SetLocal + | Operation::Test + | Operation::TestSet + | Operation::Jump + | Operation::Return => true, + } } pub fn disassembly_info(&self, chunk: &Chunk) -> String { @@ -552,22 +713,45 @@ impl Instruction { } } +impl From<&Instruction> for u64 { + fn from(instruction: &Instruction) -> Self { + instruction.0 + } +} + #[cfg(test)] mod tests { use super::*; #[test] - fn r#move() { - let mut instruction = Instruction::r#move(4, 1); + fn builder() { + let instruction_from_builder = Instruction::builder(Operation::Add) + .a(1) + .b(2) + .c(3) + .b_is_constant(true) + .c_is_constant(true) + .a_is_local(true) + .b_is_local(true) + .c_is_local(true) + .build(); + let instruction = *Instruction::add(1, 2, 3) + .set_b_is_constant() + .set_c_is_constant() + .set_a_is_local() + .set_b_is_local() + .set_c_is_local(); - instruction.set_b_is_constant(); - instruction.set_c_is_constant(); + assert_eq!(instruction_from_builder, instruction); + } + + #[test] + fn r#move() { + let instruction = Instruction::r#move(4, 1); assert_eq!(instruction.operation(), Operation::Move); - assert_eq!(instruction.a(), 4); - assert_eq!(instruction.b(), 1); - assert!(instruction.b_is_constant()); - assert!(instruction.b_is_constant()); + assert_eq!(instruction.b(), 4); + assert_eq!(instruction.c(), 1); } #[test] @@ -623,22 +807,18 @@ mod tests { #[test] fn declare_local() { - let mut instruction = Instruction::define_local(4, 1, true); - - instruction.set_b_is_constant(); + let instruction = *Instruction::define_local(4, 1, true).set_b_is_constant(); assert_eq!(instruction.operation(), Operation::DefineLocal); assert_eq!(instruction.a(), 4); assert_eq!(instruction.b(), 1); - assert_eq!(instruction.c(), true as u16); + assert!(instruction.c_as_boolean()); assert!(instruction.b_is_constant()); } #[test] fn add() { - let mut instruction = Instruction::add(1, 1, 4); - - instruction.set_b_is_constant(); + let instruction = *Instruction::add(1, 1, 4).set_b_is_constant(); assert_eq!(instruction.operation(), Operation::Add); assert_eq!(instruction.a(), 1); diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 76ba50d..736452d 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -21,7 +21,7 @@ pub use crate::compiler::{compile, CompileError, Compiler}; pub use crate::disassembler::Disassembler; pub use crate::dust_error::{AnnotatedError, DustError}; pub use crate::formatter::{format, Formatter}; -pub use crate::instruction::Instruction; +pub use crate::instruction::{Instruction, InstructionBuilder}; pub use crate::lexer::{lex, LexError, Lexer}; pub use crate::native_function::{NativeFunction, NativeFunctionError}; pub use crate::operation::Operation; diff --git a/dust-lang/src/optimizer.rs b/dust-lang/src/optimizer.rs index 36b7448..a660a9e 100644 --- a/dust-lang/src/optimizer.rs +++ b/dust-lang/src/optimizer.rs @@ -1,6 +1,6 @@ //! Tool used by the compiler to optimize a chunk's bytecode. -use crate::{Chunk, Instruction, Operation, Span}; +use crate::{instruction::InstructionBuilder, Chunk, Instruction, Operation, Span}; /// An instruction optimizer that mutably borrows instructions from a chunk. #[derive(Debug)] @@ -58,11 +58,11 @@ impl<'a> Optimizer<'a> { let first_loader_register = first_loader.a(); let second_loader = &mut instructions.last_mut().unwrap().0; - let mut second_loader_new = Instruction::with_operation(second_loader.operation()); - - second_loader_new.set_a(first_loader_register); - second_loader_new.set_b(second_loader.b()); - second_loader_new.set_c(second_loader.c()); + let second_loader_new = Instruction::builder(second_loader.operation()) + .a(first_loader_register) + .b(second_loader.b()) + .c(second_loader.c()) + .build(); *second_loader = second_loader_new; @@ -89,22 +89,12 @@ impl<'a> Optimizer<'a> { let instructions = self.instructions_mut(); let set_local = instructions.pop().unwrap().0; let set_local_register = set_local.a(); - let math_instruction = &mut instructions.last_mut().unwrap().0; - let mut math_instruction_new = Instruction::with_operation(math_instruction.operation()); + let math_instruction = instructions.last_mut().unwrap().0; + let math_instruction_new = InstructionBuilder::from(&math_instruction) + .a(set_local_register) + .build(); - math_instruction_new.set_a(set_local_register); - math_instruction_new.set_b(math_instruction.b()); - math_instruction_new.set_c(math_instruction.c()); - - if math_instruction.b_is_constant() { - math_instruction_new.set_b_is_constant(); - } - - if math_instruction.c_is_constant() { - math_instruction_new.set_c_is_constant(); - } - - *math_instruction = math_instruction_new; + instructions.last_mut().unwrap().0 = math_instruction_new; true } diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index a04f895..5d64a59 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -365,8 +365,8 @@ impl Ord for Type { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct FunctionType { - pub type_parameters: Option>, - pub value_parameters: Option>, + pub type_parameters: Option>, + pub value_parameters: Option>, pub return_type: Box, } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index cab14e3..4d83492 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -33,10 +33,10 @@ pub struct Vm<'a> { chunk: &'a Chunk, stack: Vec, parent: Option<&'a Vm<'a>>, - local_definitions: Vec>, + local_definitions: Vec>, ip: usize, - last_assigned_register: Option, + last_assigned_register: Option, current_position: Span, } @@ -387,7 +387,7 @@ impl<'a> Vm<'a> { (first_argument_index..last_argument_index).enumerate() { function_vm.set_register( - argument_index as u8, + argument_index as u16, Register::Pointer(Pointer::ParentStack(argument_register_index)), )? } @@ -474,7 +474,7 @@ impl<'a> Vm<'a> { } } - fn open_register(&self, register_index: u8) -> Result { + fn open_register(&self, register_index: u16) -> Result { let register_index = register_index as usize; let register = self.stack @@ -499,7 +499,7 @@ impl<'a> Vm<'a> { pub(crate) fn open_register_allow_empty( &self, - register_index: u8, + register_index: u16, ) -> Result, VmError> { let register_index = register_index as usize; let register = @@ -533,7 +533,7 @@ impl<'a> Vm<'a> { } /// DRY helper to get a constant or register values - fn get_argument(&self, index: u8, is_constant: bool) -> Result<&ConcreteValue, VmError> { + fn get_argument(&self, index: u16, is_constant: bool) -> Result<&ConcreteValue, VmError> { let argument = if is_constant { self.get_constant(index)? } else { @@ -562,7 +562,7 @@ impl<'a> Vm<'a> { Ok((left, right)) } - fn set_register(&mut self, to_register: u8, register: Register) -> Result<(), VmError> { + fn set_register(&mut self, to_register: u16, register: Register) -> Result<(), VmError> { self.last_assigned_register = Some(to_register); let length = self.stack.len(); @@ -607,7 +607,7 @@ impl<'a> Vm<'a> { } } - fn get_constant(&self, index: u8) -> Result<&ConcreteValue, VmError> { + fn get_constant(&self, index: u16) -> Result<&ConcreteValue, VmError> { self.chunk .get_constant(index) .map_err(|error| VmError::Chunk { @@ -654,10 +654,10 @@ impl Display for Register { #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Pointer { - Stack(u8), - Constant(u8), - ParentStack(u8), - ParentConstant(u8), + Stack(u16), + Constant(u16), + ParentStack(u16), + ParentConstant(u16), } impl Display for Pointer { @@ -701,7 +701,7 @@ pub enum VmError { // Local errors UndefinedLocal { - local_index: u8, + local_index: u16, position: Span, },