Continue register proof of concept

This commit is contained in:
Jeff 2024-09-15 01:24:04 -04:00
parent ba80774e7b
commit d1bdabed56
4 changed files with 515 additions and 229 deletions

View File

@ -154,17 +154,16 @@ impl Chunk {
pub fn define_local( pub fn define_local(
&mut self, &mut self,
local_index: usize, local_index: u8,
register_index: u8, register_index: u8,
position: Span, position: Span,
) -> Result<(), ChunkError> { ) -> Result<(), ChunkError> {
let local = let local = self.locals.get_mut(local_index as usize).ok_or_else(|| {
self.locals ChunkError::LocalIndexOutOfBounds {
.get_mut(local_index) index: local_index as usize,
.ok_or_else(|| ChunkError::LocalIndexOutOfBounds { position,
index: local_index, }
position, })?;
})?;
local.register_index = Some(register_index); local.register_index = Some(register_index);
@ -319,7 +318,7 @@ impl<'a> ChunkDisassembler<'a> {
for (offset, (instruction, position)) in self.chunk.instructions.iter().enumerate() { for (offset, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
let position = position.to_string(); let position = position.to_string();
let operation = instruction.operation.to_string(); let operation = instruction.operation().to_string();
let info_option = instruction.disassembly_info(Some(self.chunk)); let info_option = instruction.disassembly_info(Some(self.chunk));
let instruction_display = if let Some(info) = info_option { let instruction_display = if let Some(info) = info_option {
format!("{offset:<7} {operation:14} {info:25} {position:8}") format!("{offset:<7} {operation:14} {info:25} {position:8}")

View File

@ -2,112 +2,166 @@ use std::fmt::{self, Display, Formatter};
use crate::{Chunk, Span}; use crate::{Chunk, Span};
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Instruction { pub struct Instruction(u32);
pub operation: Operation,
pub destination: u8,
pub arguments: [u8; 2],
}
impl Instruction { impl Instruction {
pub fn r#move(to_register: u8, from_register: u8) -> Instruction { pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Move as u32);
operation: Operation::Move,
destination: to_register, instruction.set_destination(to_register);
arguments: [from_register, 0], instruction.set_first_argument(from_register);
}
instruction
} }
pub fn close(to_register: u8) -> Instruction { pub fn close(to_register: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Close as u32);
operation: Operation::Close,
destination: to_register, instruction.set_destination(to_register);
arguments: [0, 0],
} instruction
} }
pub fn load_constant(to_register: u8, constant_index: u8) -> Instruction { pub fn load_constant(to_register: u8, constant_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::LoadConstant as u32);
operation: Operation::LoadConstant,
destination: to_register, instruction.set_destination(to_register);
arguments: [constant_index, 0], instruction.set_first_argument(constant_index);
}
instruction
} }
pub fn declare_local(to_register: u8, variable_index: u8) -> Instruction { pub fn declare_local(to_register: u8, variable_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::DeclareLocal as u32);
operation: Operation::DeclareLocal,
destination: to_register, instruction.set_destination(to_register);
arguments: [variable_index, 0], instruction.set_first_argument(variable_index);
}
instruction
} }
pub fn get_local(to_register: u8, variable_index: u8) -> Instruction { pub fn get_local(to_register: u8, variable_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::GetLocal as u32);
operation: Operation::GetLocal,
destination: to_register, instruction.set_destination(to_register);
arguments: [variable_index, 0], instruction.set_first_argument(variable_index);
}
instruction
} }
pub fn set_local(from_register: u8, variable_index: u8) -> Instruction { pub fn set_local(from_register: u8, variable_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::SetLocal as u32);
operation: Operation::SetLocal,
destination: from_register, instruction.set_destination(from_register);
arguments: [variable_index, 0], instruction.set_first_argument(variable_index);
}
instruction
} }
pub fn add(to_register: u8, left_register: u8, right_register: u8) -> Instruction { pub fn add(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Add as u32);
operation: Operation::Add,
destination: to_register, instruction.set_destination(to_register);
arguments: [left_register, right_register], instruction.set_first_argument(left_index);
} instruction.set_second_argument(right_index);
instruction
} }
pub fn subtract(to_register: u8, left_register: u8, right_register: u8) -> Instruction { pub fn subtract(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Subtract as u32);
operation: Operation::Subtract,
destination: to_register, instruction.set_destination(to_register);
arguments: [left_register, right_register], instruction.set_first_argument(left_index);
} instruction.set_second_argument(right_index);
instruction
} }
pub fn multiply(to_register: u8, left_register: u8, right_register: u8) -> Instruction { pub fn multiply(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Multiply as u32);
operation: Operation::Multiply,
destination: to_register, instruction.set_destination(to_register);
arguments: [left_register, right_register], instruction.set_first_argument(left_index);
} instruction.set_second_argument(right_index);
instruction
} }
pub fn divide(to_register: u8, left_register: u8, right_register: u8) -> Instruction { pub fn divide(to_register: u8, left_index: u8, right_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Divide as u32);
operation: Operation::Divide,
destination: to_register, instruction.set_destination(to_register);
arguments: [left_register, right_register], instruction.set_first_argument(left_index);
} instruction.set_second_argument(right_index);
instruction
} }
pub fn negate(to_register: u8, from_register: u8) -> Instruction { pub fn negate(to_register: u8, from_index: u8) -> Instruction {
Instruction { let mut instruction = Instruction(Operation::Negate as u32);
operation: Operation::Negate,
destination: to_register, instruction.set_destination(to_register);
arguments: [from_register, 0], instruction.set_first_argument(from_index);
}
instruction
} }
pub fn r#return() -> Instruction { pub fn r#return() -> Instruction {
Instruction { Instruction(Operation::Return as u32)
operation: Operation::Return, }
destination: 0,
arguments: [0, 0], pub fn set_first_argument_to_constant(&mut self) {
} self.0 |= 0b1000_0000;
}
pub fn first_argument_is_constant(&self) -> bool {
self.0 & 0b1000_0000 != 0
}
pub fn set_second_argument_to_constant(&mut self) {
self.0 |= 0b0100_0000;
}
pub fn second_argument_is_constant(&self) -> bool {
self.0 & 0b0100_0000 != 0
}
pub fn destination(&self) -> u8 {
(self.0 >> 24) as u8
}
pub fn set_destination(&mut self, destination: u8) {
self.0 |= (destination as u32) << 24;
}
pub fn first_argument(&self) -> u8 {
(self.0 >> 16) as u8
}
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 set_second_argument(&mut self, argument: u8) {
self.0 |= (argument as u32) << 8;
}
pub fn operation(&self) -> Operation {
Operation::from((self.0 & 0b0000_0000_0011_1111) as u8)
}
pub fn set_operation(&mut self, operation: Operation) {
self.0 |= u8::from(operation) as u32;
} }
pub fn disassemble(&self, chunk: &Chunk) -> String { pub fn disassemble(&self, chunk: &Chunk) -> String {
let mut disassembled = format!("{:16} ", self.operation.to_string()); let mut disassembled = format!("{:16} ", self.operation().to_string());
if let Some(info) = self.disassembly_info(Some(chunk)) { if let Some(info) = self.disassembly_info(Some(chunk)) {
disassembled.push_str(&info); disassembled.push_str(&info);
@ -117,30 +171,37 @@ impl Instruction {
} }
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> { pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> {
let info = match self.operation { let info = match self.operation() {
Operation::Move => { Operation::Move => {
format!("R({}) = R({})", self.destination, self.arguments[0]) format!("R({}) = R({})", self.destination(), self.first_argument())
} }
Operation::Close => format!("R({})", self.destination), Operation::Close => format!("R({})", self.destination()),
Operation::LoadConstant => { Operation::LoadConstant => {
let constant_index = self.arguments[0]; let constant_index = self.first_argument();
if let Some(chunk) = chunk { if let Some(chunk) = chunk {
match chunk.get_constant(constant_index, Span(0, 0)) { match chunk.get_constant(constant_index, Span(0, 0)) {
Ok(value) => { Ok(value) => {
format!("R({}) = C({}) {}", self.destination, constant_index, value) format!(
"R({}) = C({}) {}",
self.destination(),
constant_index,
value
)
} }
Err(error) => format!( Err(error) => format!(
"R({}) = C({}) {:?}", "R({}) = C({}) {:?}",
self.destination, constant_index, error self.destination(),
constant_index,
error
), ),
} }
} else { } else {
format!("R({}) = C({})", self.destination, constant_index) format!("R({}) = C({})", self.destination(), constant_index)
} }
} }
Operation::DeclareLocal => { Operation::DeclareLocal => {
let local_index = self.arguments[0]; let local_index = self.first_argument();
let identifier_display = if let Some(chunk) = chunk { let identifier_display = if let Some(chunk) = chunk {
match chunk.get_identifier(local_index) { match chunk.get_identifier(local_index) {
Some(identifier) => identifier.to_string(), Some(identifier) => identifier.to_string(),
@ -152,16 +213,18 @@ impl Instruction {
format!( format!(
"L({}) = R({}) {}", "L({}) = R({}) {}",
local_index, self.destination, identifier_display local_index,
self.destination(),
identifier_display
) )
} }
Operation::GetLocal => { Operation::GetLocal => {
let local_index = self.arguments[0]; let local_index = self.first_argument();
format!("R({}) = L({})", self.destination, local_index) format!("R({}) = L({})", self.destination(), local_index)
} }
Operation::SetLocal => { Operation::SetLocal => {
let local_index = self.arguments[0]; let local_index = self.first_argument();
let identifier_display = if let Some(chunk) = chunk { let identifier_display = if let Some(chunk) = chunk {
match chunk.get_identifier(local_index) { match chunk.get_identifier(local_index) {
Some(identifier) => identifier.to_string(), Some(identifier) => identifier.to_string(),
@ -173,35 +236,73 @@ impl Instruction {
format!( format!(
"L({}) = R({}) {}", "L({}) = R({}) {}",
local_index, self.destination, identifier_display local_index,
self.destination(),
identifier_display
) )
} }
Operation::Add => { Operation::Add => {
format!( let destination = self.destination();
"R({}) = RC({}) + RC({})", let first_argument = if self.first_argument_is_constant() {
self.destination, self.arguments[0], self.arguments[1] format!("C({})", self.first_argument())
) } else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} + {second_argument}",)
} }
Operation::Subtract => { Operation::Subtract => {
format!( let destination = self.destination();
"R({}) = RC({}) - RC({})", let first_argument = if self.first_argument_is_constant() {
self.destination, self.arguments[0], self.arguments[1] format!("C({})", self.first_argument())
) } else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} - {second_argument}",)
} }
Operation::Multiply => { Operation::Multiply => {
format!( let destination = self.destination();
"R({}) = RC({}) * RC({})", let first_argument = if self.first_argument_is_constant() {
self.destination, self.arguments[0], self.arguments[1] format!("C({})", self.first_argument())
) } else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} * {second_argument}",)
} }
Operation::Divide => { Operation::Divide => {
format!( let destination = self.destination();
"R({}) = RC({}) / RC({})", let first_argument = if self.first_argument_is_constant() {
self.destination, self.arguments[0], self.arguments[1] format!("C({})", self.first_argument())
) } else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} / {second_argument}",)
} }
Operation::Negate => { Operation::Negate => {
format!("R({}) = -RC({})", self.destination, self.arguments[0]) format!("R({}) = -RC({})", self.destination(), self.first_argument())
} }
Operation::Return => return None, Operation::Return => return None,
}; };
@ -213,38 +314,51 @@ impl Instruction {
impl Display for Instruction { impl Display for Instruction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if let Some(info) = self.disassembly_info(None) { if let Some(info) = self.disassembly_info(None) {
write!(f, "{} {}", self.operation, info) write!(f, "{} {}", self.operation(), info)
} else { } else {
write!(f, "{}", self.operation) write!(f, "{}", self.operation())
} }
} }
} }
const MOVE: u8 = 0b0000_0000;
const CLOSE: u8 = 0b000_0001;
const LOAD_CONSTANT: u8 = 0b0000_0010;
const DECLARE_LOCAL: u8 = 0b0000_0011;
const GET_LOCAL: u8 = 0b0000_0100;
const SET_LOCAL: u8 = 0b0000_0101;
const ADD: u8 = 0b0000_0110;
const SUBTRACT: u8 = 0b0000_0111;
const MULTIPLY: u8 = 0b0000_1000;
const DIVIDE: u8 = 0b0000_1001;
const NEGATE: u8 = 0b0000_1010;
const RETURN: u8 = 0b0000_1011;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operation { pub enum Operation {
// Stack manipulation // Stack manipulation
Move = 0, Move = MOVE as isize,
Close = 1, Close = CLOSE as isize,
// Constants // Constants
LoadConstant = 2, LoadConstant = LOAD_CONSTANT as isize,
// Variables // Variables
DeclareLocal = 3, DeclareLocal = DECLARE_LOCAL as isize,
GetLocal = 4, GetLocal = GET_LOCAL as isize,
SetLocal = 5, SetLocal = SET_LOCAL as isize,
// Binary operations // Binary operations
Add = 6, Add = ADD as isize,
Subtract = 7, Subtract = SUBTRACT as isize,
Multiply = 8, Multiply = MULTIPLY as isize,
Divide = 9, Divide = DIVIDE as isize,
// Unary operations // Unary operations
Negate = 10, Negate = NEGATE as isize,
// Control flow // Control flow
Return = 11, Return = RETURN as isize,
} }
impl Operation { impl Operation {
@ -259,22 +373,41 @@ impl Operation {
impl From<u8> for Operation { impl From<u8> for Operation {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte {
0 => Operation::Move, MOVE => Operation::Move,
1 => Operation::Close, CLOSE => Operation::Close,
2 => Operation::LoadConstant, LOAD_CONSTANT => Operation::LoadConstant,
3 => Operation::DeclareLocal, DECLARE_LOCAL => Operation::DeclareLocal,
4 => Operation::GetLocal, GET_LOCAL => Operation::GetLocal,
5 => Operation::SetLocal, SET_LOCAL => Operation::SetLocal,
6 => Operation::Add, ADD => Operation::Add,
7 => Operation::Subtract, SUBTRACT => Operation::Subtract,
8 => Operation::Multiply, MULTIPLY => Operation::Multiply,
9 => Operation::Divide, DIVIDE => Operation::Divide,
10 => Operation::Negate, NEGATE => Operation::Negate,
_ => Operation::Return, _ => Operation::Return,
} }
} }
} }
impl From<Operation> for u8 {
fn from(operation: Operation) -> Self {
match operation {
Operation::Move => MOVE,
Operation::Close => CLOSE,
Operation::LoadConstant => LOAD_CONSTANT,
Operation::DeclareLocal => DECLARE_LOCAL,
Operation::GetLocal => GET_LOCAL,
Operation::SetLocal => SET_LOCAL,
Operation::Add => ADD,
Operation::Subtract => SUBTRACT,
Operation::Multiply => MULTIPLY,
Operation::Divide => DIVIDE,
Operation::Negate => NEGATE,
Operation::Return => RETURN,
}
}
}
impl Display for Operation { impl Display for Operation {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
@ -296,12 +429,157 @@ impl Display for Operation {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::mem::size_of;
use super::*; use super::*;
#[test] #[test]
fn instruction_is_32_bits() { fn r#move() {
assert_eq!(size_of::<Instruction>(), 4); let mut instruction = Instruction::r#move(255, 255);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Move);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn close() {
let mut instruction = Instruction::close(255);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Close);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn load_constant() {
let mut instruction = Instruction::load_constant(255, 255);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::LoadConstant);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn declare_local() {
let mut instruction = Instruction::declare_local(255, 255);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::DeclareLocal);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn add() {
let mut instruction = Instruction::add(255, 255, 2);
instruction.set_operation(Operation::Add);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Add);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert_eq!(instruction.second_argument(), 2);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn subtract() {
let mut instruction = Instruction::subtract(255, 255, 255);
instruction.set_operation(Operation::Subtract);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Subtract);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert_eq!(instruction.second_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn multiply() {
let mut instruction = Instruction::multiply(255, 255, 255);
instruction.set_operation(Operation::Multiply);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Multiply);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert_eq!(instruction.second_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn divide() {
let mut instruction = Instruction::divide(255, 255, 255);
instruction.set_operation(Operation::Divide);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Divide);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert_eq!(instruction.second_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn negate() {
let mut instruction = Instruction::negate(255, 255);
instruction.set_operation(Operation::Negate);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Negate);
assert_eq!(instruction.destination(), 255);
assert_eq!(instruction.first_argument(), 255);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
}
#[test]
fn r#return() {
let mut instruction = Instruction::r#return();
instruction.set_operation(Operation::Return);
instruction.set_first_argument_to_constant();
instruction.set_second_argument_to_constant();
assert_eq!(instruction.operation(), Operation::Return);
assert!(instruction.first_argument_is_constant());
assert!(instruction.second_argument_is_constant());
} }
} }

View File

@ -258,15 +258,11 @@ impl<'src> Parser<'src> {
let mut push_back_right = false; let mut push_back_right = false;
let (right_instruction, right_position) = let (right_instruction, right_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let right_register = match right_instruction { let right = match right_instruction.operation() {
Instruction { Operation::LoadConstant => {
operation: Operation::LoadConstant,
arguments,
..
} => {
self.decrement_register()?; self.decrement_register()?;
arguments[0] right_instruction.first_argument()
} }
_ => { _ => {
push_back_right = true; push_back_right = true;
@ -277,15 +273,11 @@ impl<'src> Parser<'src> {
let mut push_back_left = false; let mut push_back_left = false;
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let left_register = match left_instruction { let left = match left_instruction.operation() {
Instruction { Operation::LoadConstant => {
operation: Operation::LoadConstant,
arguments,
..
} => {
self.decrement_register()?; self.decrement_register()?;
arguments[0] left_instruction.first_argument()
} }
_ => { _ => {
push_back_left = true; push_back_left = true;
@ -294,28 +286,19 @@ impl<'src> Parser<'src> {
} }
}; };
if push_back_right {
self.chunk
.push_instruction(right_instruction, right_position);
}
if push_back_left { if push_back_left {
self.chunk.push_instruction(left_instruction, left_position); self.emit_instruction(left_instruction, left_position);
} }
let instruction = match operator { if push_back_right {
TokenKind::Plus => { self.emit_instruction(right_instruction, right_position);
Instruction::add(self.current_register, left_register, right_register) }
}
TokenKind::Minus => { let mut instruction = match operator {
Instruction::subtract(self.current_register, left_register, right_register) TokenKind::Plus => Instruction::add(self.current_register, left, right),
} TokenKind::Minus => Instruction::subtract(self.current_register, left, right),
TokenKind::Star => { TokenKind::Star => Instruction::multiply(self.current_register, left, right),
Instruction::multiply(self.current_register, left_register, right_register) TokenKind::Slash => Instruction::divide(self.current_register, left, right),
}
TokenKind::Slash => {
Instruction::divide(self.current_register, left_register, right_register)
}
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
expected: vec![ expected: vec![
@ -330,6 +313,14 @@ impl<'src> Parser<'src> {
} }
}; };
if !push_back_left {
instruction.set_first_argument_to_constant();
}
if !push_back_right {
instruction.set_second_argument_to_constant();
}
self.increment_register()?; self.increment_register()?;
self.emit_instruction(instruction, operator_position); self.emit_instruction(instruction, operator_position);
@ -351,14 +342,14 @@ impl<'src> Parser<'src> {
let (mut previous_instruction, previous_position) = let (mut previous_instruction, previous_position) =
self.chunk.pop_instruction(self.previous_position)?; self.chunk.pop_instruction(self.previous_position)?;
if previous_instruction.operation.is_binary() { if previous_instruction.operation().is_binary() {
let previous_register = self let previous_register = self
.chunk .chunk
.get_local(local_index, start_position)? .get_local(local_index, start_position)?
.register_index; .register_index;
if let Some(register_index) = previous_register { if let Some(register_index) = previous_register {
previous_instruction.destination = register_index; previous_instruction.set_destination(register_index);
self.emit_instruction(previous_instruction, self.previous_position); self.emit_instruction(previous_instruction, self.previous_position);
self.decrement_register()?; self.decrement_register()?;
@ -483,23 +474,15 @@ impl<'src> Parser<'src> {
let (previous_instruction, previous_position) = let (previous_instruction, previous_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
if let Instruction { if let Operation::GetLocal = previous_instruction.operation() {
operation: Operation::GetLocal, let move_instruction = Instruction::r#move(
destination, previous_instruction.destination(),
arguments, previous_instruction.first_argument(),
} = previous_instruction
{
self.emit_instruction(
Instruction {
operation: Operation::Move,
destination,
arguments,
},
position,
); );
self.emit_instruction(move_instruction, position);
} else { } else {
self.chunk self.emit_instruction(previous_instruction, previous_position);
.push_instruction(previous_instruction, previous_position);
} }
self.emit_instruction( self.emit_instruction(

View File

@ -38,31 +38,31 @@ impl Vm {
while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() { while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() {
log::trace!("Running instruction {instruction} at {position}"); log::trace!("Running instruction {instruction} at {position}");
match instruction.operation { match instruction.operation() {
Operation::Move => { Operation::Move => {
let from = instruction.arguments[0]; let from = instruction.first_argument();
let to = instruction.destination; let to = instruction.destination();
let value = self.clone(from, position)?; let value = self.clone(from, position)?;
self.insert(value, to, position)?; self.insert(value, to, position)?;
} }
Operation::Close => todo!(), Operation::Close => todo!(),
Operation::LoadConstant => { Operation::LoadConstant => {
let to_register = instruction.destination; let to_register = instruction.destination();
let from_constant = instruction.arguments[0]; let from_constant = instruction.first_argument();
let value = self.chunk.take_constant(from_constant, position)?; let value = self.chunk.take_constant(from_constant, position)?;
self.insert(value, to_register, position)?; self.insert(value, to_register, position)?;
} }
Operation::DeclareLocal => { Operation::DeclareLocal => {
let from_register = instruction.destination; let from_register = instruction.destination();
let to_local = u16::from_le_bytes(instruction.arguments) as usize; let to_local = instruction.first_argument();
self.chunk.define_local(to_local, from_register, position)?; self.chunk.define_local(to_local, from_register, position)?;
} }
Operation::GetLocal => { Operation::GetLocal => {
let register_index = instruction.destination; let register_index = instruction.destination();
let local_index = instruction.arguments[0]; let local_index = instruction.first_argument();
let local = self.chunk.get_local(local_index, position)?; let local = self.chunk.get_local(local_index, position)?;
let value = if let Some(value_index) = &local.register_index { let value = if let Some(value_index) = &local.register_index {
self.clone(*value_index, position)? self.clone(*value_index, position)?
@ -76,63 +76,90 @@ impl Vm {
self.insert(value, register_index, position)?; self.insert(value, register_index, position)?;
} }
Operation::SetLocal => { Operation::SetLocal => {
let from_register = instruction.destination; let from_register = instruction.destination();
let to_local = instruction.arguments[0] as usize; let to_local = instruction.first_argument();
self.chunk.define_local(to_local, from_register, position)?; self.chunk.define_local(to_local, from_register, position)?;
} }
Operation::Add => { Operation::Add => {
let left = let left = self.take_constant_or_clone_register(
self.take_constant_or_clone_register(instruction.arguments[0], position)?; instruction.first_argument(),
let right = instruction.first_argument_is_constant(),
self.take_constant_or_clone_register(instruction.arguments[1], position)?; position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let sum = left let sum = left
.add(&right) .add(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(sum, instruction.destination, position)?; self.insert(sum, instruction.destination(), position)?;
} }
Operation::Subtract => { Operation::Subtract => {
let left = let left = self.take_constant_or_clone_register(
self.take_constant_or_clone_register(instruction.arguments[0], position)?; instruction.first_argument(),
let right = instruction.first_argument_is_constant(),
self.take_constant_or_clone_register(instruction.arguments[1], position)?; position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let difference = left let difference = left
.subtract(&right) .subtract(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(difference, instruction.destination, position)?; self.insert(difference, instruction.destination(), position)?;
} }
Operation::Multiply => { Operation::Multiply => {
let left = let left = self.take_constant_or_clone_register(
self.take_constant_or_clone_register(instruction.arguments[0], position)?; instruction.first_argument(),
let right = instruction.first_argument_is_constant(),
self.take_constant_or_clone_register(instruction.arguments[1], position)?; position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let product = left let product = left
.multiply(&right) .multiply(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(product, instruction.destination, position)?; self.insert(product, instruction.destination(), position)?;
} }
Operation::Divide => { Operation::Divide => {
let left = let left = self.take_constant_or_clone_register(
self.take_constant_or_clone_register(instruction.arguments[0], position)?; instruction.first_argument(),
let right = instruction.first_argument_is_constant(),
self.take_constant_or_clone_register(instruction.arguments[1], position)?; position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let quotient = left let quotient = left
.divide(&right) .divide(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(quotient, instruction.destination, position)?; self.insert(quotient, instruction.destination(), position)?;
} }
Operation::Negate => { Operation::Negate => {
let value = let value = self.take_constant_or_clone_register(
self.take_constant_or_clone_register(instruction.arguments[0], position)?; instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let negated = value let negated = value
.negate() .negate()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(negated, instruction.destination, position)?; self.insert(negated, instruction.destination(), position)?;
} }
Operation::Return => { Operation::Return => {
let value = self.pop(position)?; let value = self.pop(position)?;
@ -186,14 +213,13 @@ impl Vm {
fn take_constant_or_clone_register( fn take_constant_or_clone_register(
&mut self, &mut self,
index: u8, index: u8,
is_constant: bool,
position: Span, position: Span,
) -> Result<Value, VmError> { ) -> Result<Value, VmError> {
if let Ok(value) = self.chunk.take_constant(index, position) { if is_constant {
Ok(value) Ok(self.chunk.take_constant(index, position)?)
} else { } else {
let value = self.clone(index, position)?; self.clone(index, position)
Ok(value)
} }
} }