1
0

Use Operand type to store instruction argument types

This commit is contained in:
Jeff 2025-02-07 10:19:38 -05:00
parent b90adcb9f0
commit 25b4230aa4
12 changed files with 213 additions and 387 deletions

View File

@ -785,7 +785,7 @@ impl<'src> Compiler<'src> {
let (previous_instruction, previous_type, previous_position) =
self.instructions.pop().unwrap();
let (argument, push_back) = self.handle_binary_argument(&previous_instruction)?;
let (argument, push_back) = self.handle_binary_argument(&previous_instruction);
if push_back {
self.instructions.push((
@ -832,48 +832,10 @@ impl<'src> Compiler<'src> {
Ok(())
}
fn handle_binary_argument(
&mut self,
instruction: &Instruction,
) -> Result<(Operand, bool), CompileError> {
let (argument, push_back) = match instruction.operation() {
Operation::LOAD_CONSTANT => (Operand::Constant(instruction.b_field()), false),
Operation::POINT => (instruction.b_as_operand(), false),
Operation::LOAD_ENCODED
| Operation::LOAD_LIST
| Operation::LOAD_SELF
| Operation::ADD
| Operation::SUBTRACT
| Operation::MULTIPLY
| Operation::DIVIDE
| Operation::MODULO
| Operation::EQUAL
| Operation::LESS
| Operation::LESS_EQUAL
| Operation::NEGATE
| Operation::NOT
| Operation::CALL => (Operand::Register(instruction.a_field()), true),
Operation::CALL_NATIVE => {
let function = NativeFunction::from(instruction.b_field());
fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
let (argument, push_back) = (instruction.as_operand(), !instruction.yields_value());
if function.returns_value() {
(Operand::Register(instruction.a_field()), true)
} else {
return Err(CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
}
_ => {
return Err(CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
};
Ok((argument, push_back))
(argument, push_back)
}
fn parse_math_binary(&mut self) -> Result<(), CompileError> {
@ -884,7 +846,7 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?;
let (left, push_back_left) = self.handle_binary_argument(&left_instruction);
let left_is_mutable_local = if left_instruction.operation() == Operation::POINT {
let Point { to, .. } = Point::from(left_instruction);
@ -915,13 +877,13 @@ impl<'src> Compiler<'src> {
check_math_type(&left_type, operator, &left_position)?;
let (left_type_code, destination) = match left_type {
Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()),
Type::Byte => (TypeCode::BYTE, self.next_byte_register()),
Type::Character => (TypeCode::CHARACTER, self.next_character_register()),
Type::Float => (TypeCode::FLOAT, self.next_float_register()),
Type::Integer => (TypeCode::INTEGER, self.next_integer_register()),
Type::String => (TypeCode::STRING, self.next_string_register()),
let destination = match left_type {
Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(),
Type::Float => self.next_float_register(),
Type::Integer => self.next_integer_register(),
Type::String => self.next_string_register(),
_ => unreachable!(),
};
@ -936,7 +898,7 @@ impl<'src> Compiler<'src> {
self.parse_sub_expression(&rule.precedence)?;
let (right_instruction, right_type, right_position) = self.instructions.pop().unwrap();
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
let (right, push_back_right) = self.handle_binary_argument(&right_instruction);
check_math_type(&right_type, operator, &right_position)?;
check_math_types(
@ -947,16 +909,6 @@ impl<'src> Compiler<'src> {
&right_position,
)?;
let right_type_code = match right_type {
Type::Boolean => TypeCode::BOOLEAN,
Type::Byte => TypeCode::BYTE,
Type::Character => TypeCode::CHARACTER,
Type::Float => TypeCode::FLOAT,
Type::Integer => TypeCode::INTEGER,
Type::String => TypeCode::STRING,
_ => unreachable!(),
};
if push_back_right {
self.instructions
.push((right_instruction, right_type, right_position));
@ -970,21 +922,11 @@ impl<'src> Compiler<'src> {
left_type.clone()
};
let instruction = match operator {
Token::Plus | Token::PlusEqual => {
Instruction::add(destination, left, left_type_code, right, right_type_code)
}
Token::Minus | Token::MinusEqual => {
Instruction::subtract(destination, left, left_type_code, right, right_type_code)
}
Token::Star | Token::StarEqual => {
Instruction::multiply(destination, left, left_type_code, right, right_type_code)
}
Token::Slash | Token::SlashEqual => {
Instruction::divide(destination, left, left_type_code, right, right_type_code)
}
Token::Percent | Token::PercentEqual => {
Instruction::modulo(destination, left, left_type_code, right, right_type_code)
}
Token::Plus | Token::PlusEqual => Instruction::add(destination, left, right),
Token::Minus | Token::MinusEqual => Instruction::subtract(destination, left, right),
Token::Star | Token::StarEqual => Instruction::multiply(destination, left, right),
Token::Slash | Token::SlashEqual => Instruction::divide(destination, left, right),
Token::Percent | Token::PercentEqual => Instruction::modulo(destination, left, right),
_ => {
return Err(CompileError::ExpectedTokenMultiple {
expected: &[
@ -1031,23 +973,13 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?;
let (left, push_back_left) = self.handle_binary_argument(&left_instruction);
let operator = self.current_token;
let operator_position = self.current_position;
let rule = ParseRule::from(&operator);
// TODO: Check if the left type is a valid type for comparison
let left_type_code = match left_type {
Type::Boolean => TypeCode::BOOLEAN,
Type::Byte => TypeCode::BYTE,
Type::Character => TypeCode::CHARACTER,
Type::Float => TypeCode::FLOAT,
Type::Integer => TypeCode::INTEGER,
Type::String => TypeCode::STRING,
_ => unreachable!(),
};
if push_back_left {
self.instructions
.push((left_instruction, left_type, left_position));
@ -1063,21 +995,11 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
let (right, push_back_right) = self.handle_binary_argument(&right_instruction);
// TODO: Check if the right type is a valid type for comparison
// TODO: Check if the left and right types are compatible
let right_type_code = match right_type {
Type::Boolean => TypeCode::BOOLEAN,
Type::Byte => TypeCode::BYTE,
Type::Character => TypeCode::CHARACTER,
Type::Float => TypeCode::FLOAT,
Type::Integer => TypeCode::INTEGER,
Type::String => TypeCode::STRING,
_ => unreachable!(),
};
if push_back_right {
self.instructions
.push((right_instruction, right_type, right_position));
@ -1085,22 +1007,12 @@ impl<'src> Compiler<'src> {
let destination = self.next_boolean_register();
let comparison = match operator {
Token::DoubleEqual => {
Instruction::equal(true, left, left_type_code, right, right_type_code)
}
Token::BangEqual => {
Instruction::equal(false, left, left_type_code, right, right_type_code)
}
Token::Less => Instruction::less(true, left, left_type_code, right, right_type_code),
Token::LessEqual => {
Instruction::less_equal(true, left, left_type_code, right, right_type_code)
}
Token::Greater => {
Instruction::less_equal(false, left, left_type_code, right, right_type_code)
}
Token::GreaterEqual => {
Instruction::less(false, left, left_type_code, right, right_type_code)
}
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),
_ => {
return Err(CompileError::ExpectedTokenMultiple {
expected: &[
@ -1289,8 +1201,7 @@ impl<'src> Compiler<'src> {
};
let point = Instruction::point(
local_register_index,
Operand::Register(register),
r#type.type_code(),
Operand::Register(register, r#type.type_code()),
);
self.emit_instruction(point, r#type, start_position);
@ -1310,8 +1221,7 @@ impl<'src> Compiler<'src> {
};
let point = Instruction::point(
destination,
Operand::Register(local_register_index),
r#type.type_code(),
Operand::Register(local_register_index, r#type.type_code()),
);
self.emit_instruction(point, r#type, self.previous_position);
@ -1704,14 +1614,10 @@ impl<'src> Compiler<'src> {
fn parse_implicit_return(&mut self) -> Result<(), CompileError> {
if matches!(self.get_last_operation(), Some(Operation::POINT)) {
let Point {
destination,
r#type: type_code,
..
} = Point::from(self.instructions.last().unwrap().0);
let Point { destination, to } = Point::from(self.instructions.last().unwrap().0);
let (_, r#type, _) = self.instructions.pop().unwrap();
let r#return = Instruction::r#return(true, destination, type_code);
let r#return = Instruction::r#return(true, destination, to.as_type());
self.emit_instruction(r#return, r#type, self.current_position);
} else if matches!(self.get_last_operation(), Some(Operation::RETURN))

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Add {
pub destination: u16,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Add {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Add {
destination,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Add> for Instruction {
let a_field = add.destination;
let (b_field, b_is_constant) = add.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = add.right.as_index_and_constant_flag();
let b_type = add.left_type;
let c_type = add.right_type;
let b_type = add.left.as_type();
let c_type = add.right.as_type();
InstructionFields {
operation,
@ -56,15 +50,13 @@ impl Display for Add {
let Add {
destination,
left,
left_type,
right,
right_type: _,
} = self;
match *left_type {
match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Divide {
pub destination: u16,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Divide {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Divide {
destination,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Divide> for Instruction {
let a_field = divide.destination;
let (b_field, b_is_constant) = divide.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = divide.right.as_index_and_constant_flag();
let b_type = divide.left_type;
let c_type = divide.right_type;
let b_type = divide.left.as_type();
let c_type = divide.right.as_type();
InstructionFields {
operation,
@ -56,11 +50,19 @@ impl Display for Divide {
let Divide {
destination,
left,
left_type: _,
right,
right_type: _,
} = self;
write!(f, "R{destination} = {left} ÷ {right}",)
match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
_ => todo!(),
}
write!(f, " = {left} ÷ {right}",)
}
}

View File

@ -1,28 +1,22 @@
use std::fmt::{self, Display, Formatter};
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
use super::{Instruction, InstructionFields, Operand, Operation};
pub struct Equal {
pub comparator: bool,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Equal {
fn from(instruction: Instruction) -> Self {
let comparator = instruction.d_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Equal {
comparator,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Equal> for Instruction {
let (b_field, b_is_constant) = equal_bool.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = equal_bool.right.as_index_and_constant_flag();
let d_field = equal_bool.comparator;
let b_type = equal_bool.left_type;
let c_type = equal_bool.right_type;
let b_type = equal_bool.left.as_type();
let c_type = equal_bool.right.as_type();
InstructionFields {
operation,
@ -56,9 +50,7 @@ impl Display for Equal {
let Equal {
comparator,
left,
left_type: _,
right,
right_type: _,
} = self;
let operator = if *comparator { "==" } else { "" };

View File

@ -1,28 +1,22 @@
use std::fmt::{self, Display, Formatter};
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
use super::{Instruction, InstructionFields, Operand, Operation};
pub struct Less {
pub comparator: bool,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Less {
fn from(instruction: Instruction) -> Self {
let comparator = instruction.d_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Less {
comparator,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Less> for Instruction {
let (b_field, b_is_constant) = less.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = less.right.as_index_and_constant_flag();
let d_field = less.comparator;
let b_type = less.left_type;
let c_type = less.right_type;
let b_type = less.left.as_type();
let c_type = less.right.as_type();
InstructionFields {
operation,
@ -56,9 +50,7 @@ impl Display for Less {
let Less {
comparator,
left,
left_type: _,
right,
right_type: _,
} = self;
let operator = if *comparator { "<" } else { "" };

View File

@ -1,28 +1,22 @@
use std::fmt::{self, Display, Formatter};
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
use super::{Instruction, InstructionFields, Operand, Operation};
pub struct LessEqual {
pub comparator: bool,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for LessEqual {
fn from(instruction: Instruction) -> Self {
let comparator = instruction.d_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
LessEqual {
comparator,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<LessEqual> for Instruction {
let (b_field, b_is_constant) = less_equal_byte.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = less_equal_byte.right.as_index_and_constant_flag();
let d_field = less_equal_byte.comparator;
let b_type = less_equal_byte.left_type;
let c_type = less_equal_byte.right_type;
let b_type = less_equal_byte.left.as_type();
let c_type = less_equal_byte.right.as_type();
InstructionFields {
operation,
@ -56,9 +50,7 @@ impl Display for LessEqual {
let LessEqual {
comparator,
left,
left_type: _,
right,
right_type: _,
} = self;
let operator = if *comparator { "" } else { ">" };

View File

@ -278,12 +278,52 @@ impl Instruction {
*self = fields.build();
}
pub fn point(destination: u16, to: Operand, r#type: TypeCode) -> Instruction {
Instruction::from(Point {
destination,
to,
r#type,
})
pub fn as_operand(&self) -> Operand {
match self.operation() {
Operation::POINT => {
let Point { destination, to } = Point::from(*self);
Operand::Register(destination, to.as_type())
}
Operation::LOAD_ENCODED => {
let LoadEncoded {
destination,
value_type,
..
} = LoadEncoded::from(*self);
Operand::Register(destination, value_type)
}
Operation::LOAD_CONSTANT => {
let LoadConstant {
constant_type,
constant_index,
..
} = LoadConstant::from(*self);
Operand::Constant(constant_index, constant_type)
}
Operation::LOAD_LIST => {
let LoadList { destination, .. } = LoadList::from(*self);
Operand::Register(destination, TypeCode::LIST)
}
Operation::LOAD_FUNCTION => {
let LoadFunction { destination, .. } = LoadFunction::from(*self);
Operand::Register(destination, TypeCode::FUNCTION)
}
Operation::LOAD_SELF => {
let LoadSelf { destination, .. } = LoadSelf::from(*self);
Operand::Register(destination, TypeCode::FUNCTION)
}
_ => todo!(),
}
}
pub fn point(destination: u16, to: Operand) -> Instruction {
Instruction::from(Point { destination, to })
}
pub fn close(from: u16, to: u16) -> Instruction {
@ -341,131 +381,67 @@ impl Instruction {
})
}
pub fn add(
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn add(destination: u16, left: Operand, right: Operand) -> Instruction {
Instruction::from(Add {
destination,
left,
left_type,
right,
right_type,
})
}
pub fn subtract(
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn subtract(destination: u16, left: Operand, right: Operand) -> Instruction {
Instruction::from(Subtract {
destination,
left,
left_type,
right,
right_type,
})
}
pub fn multiply(
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn multiply(destination: u16, left: Operand, right: Operand) -> Instruction {
Instruction::from(Multiply {
destination,
left,
left_type,
right,
right_type,
})
}
pub fn divide(
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn divide(destination: u16, left: Operand, right: Operand) -> Instruction {
Instruction::from(Divide {
destination,
left,
left_type,
right,
right_type,
})
}
pub fn modulo(
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn modulo(destination: u16, left: Operand, right: Operand) -> Instruction {
Instruction::from(Modulo {
destination,
left,
left_type,
right,
right_type,
})
}
pub fn equal(
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn equal(comparator: bool, left: Operand, right: Operand) -> Instruction {
Instruction::from(Equal {
comparator,
left,
left_type,
right,
right_type,
})
}
pub fn less(
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn less(comparator: bool, left: Operand, right: Operand) -> Instruction {
Instruction::from(Less {
comparator,
left,
left_type,
right,
right_type,
})
}
pub fn less_equal(
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
pub fn less_equal(comparator: bool, left: Operand, right: Operand) -> Instruction {
Instruction::from(LessEqual {
comparator,
left,
left_type,
right,
right_type,
})
}
@ -552,55 +528,20 @@ impl Instruction {
self.operation().is_comparison()
}
pub fn as_argument(&self) -> Option<Operand> {
match self.operation() {
Operation::LOAD_CONSTANT => Some(Operand::Constant(self.b_field())),
Operation::POINT
| Operation::LOAD_ENCODED
| Operation::LOAD_LIST
| Operation::LOAD_SELF
| Operation::ADD
| Operation::SUBTRACT
| Operation::MULTIPLY
| Operation::DIVIDE
| Operation::MODULO
| Operation::EQUAL
| Operation::LESS
| Operation::LESS_EQUAL
| Operation::NEGATE
| Operation::NOT
| Operation::CALL => Some(Operand::Register(self.a_field())),
Operation::CALL_NATIVE => {
let function = NativeFunction::from(self.b_field());
if function.returns_value() {
Some(Operand::Register(self.a_field()))
} else {
None
}
}
_ => None,
}
}
pub fn b_as_operand(&self) -> Operand {
if self.b_is_constant() {
Operand::Constant(self.b_field())
Operand::Constant(self.b_field(), self.b_type())
} else {
Operand::Register(self.b_field())
Operand::Register(self.b_field(), self.b_type())
}
}
pub fn b_and_c_as_operands(&self) -> (Operand, Operand) {
let left = if self.b_is_constant() {
Operand::Constant(self.b_field())
} else {
Operand::Register(self.b_field())
};
let left = self.b_as_operand();
let right = if self.c_is_constant() {
Operand::Constant(self.c_field())
Operand::Constant(self.c_field(), self.c_type())
} else {
Operand::Register(self.c_field())
Operand::Register(self.c_field(), self.c_type())
};
(left, right)
@ -684,30 +625,37 @@ impl Display for Instruction {
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Operand {
Constant(u16),
Register(u16),
Constant(u16, TypeCode),
Register(u16, TypeCode),
}
impl Operand {
pub fn index(&self) -> u16 {
match self {
Operand::Constant(index) => *index,
Operand::Register(index) => *index,
Operand::Constant(index, _) => *index,
Operand::Register(index, _) => *index,
}
}
pub fn is_constant(&self) -> bool {
matches!(self, Operand::Constant(_))
matches!(self, Operand::Constant(_, _))
}
pub fn is_register(&self) -> bool {
matches!(self, Operand::Register(_))
matches!(self, Operand::Register(_, _))
}
pub fn as_index_and_constant_flag(&self) -> (u16, bool) {
match self {
Operand::Constant(index) => (*index, true),
Operand::Register(index) => (*index, false),
Operand::Constant(index, _) => (*index, true),
Operand::Register(index, _) => (*index, false),
}
}
pub fn as_type(&self) -> TypeCode {
match self {
Operand::Constant(_, r#type) => *r#type,
Operand::Register(_, r#type) => *r#type,
}
}
}
@ -715,8 +663,26 @@ impl Operand {
impl Display for Operand {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Operand::Constant(index) => write!(f, "{index}"),
Operand::Register(index) => write!(f, "{index}"),
Operand::Constant(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "C_{}", index),
TypeCode::CHARACTER => write!(f, "C_{}", index),
TypeCode::INTEGER => write!(f, "C_{}", index),
TypeCode::FLOAT => write!(f, "C_{}", index),
TypeCode::STRING => write!(f, "C_{}", index),
TypeCode::LIST => write!(f, "C_{}", index),
TypeCode::FUNCTION => write!(f, "C_{}", index),
_ => panic!("Unknown type code: {}", r#type.0),
},
Operand::Register(index, r#type) => match *r#type {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{}", index),
TypeCode::CHARACTER => write!(f, "R_CHAR_{}", index),
TypeCode::INTEGER => write!(f, "R_INT_{}", index),
TypeCode::FLOAT => write!(f, "R_FLOAT_{}", index),
TypeCode::STRING => write!(f, "R_STR_{}", index),
TypeCode::LIST => write!(f, "R_LIST_{}", index),
TypeCode::FUNCTION => write!(f, "R_FN_{}", index),
_ => panic!("Unknown type code: {}", r#type.0),
},
}
}
}
@ -729,10 +695,8 @@ mod tests {
fn decode_operation() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(instruction.operation(), Operation::ADD);
@ -742,10 +706,8 @@ mod tests {
fn decode_a_field() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(42, instruction.a_field());
@ -755,10 +717,8 @@ mod tests {
fn decode_b_field() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(4, instruction.b_field());
@ -768,10 +728,8 @@ mod tests {
fn decode_c_field() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(2, instruction.c_field());
@ -781,10 +739,8 @@ mod tests {
fn decode_d_field() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert!(!instruction.d_field());
@ -794,10 +750,8 @@ mod tests {
fn decode_b_is_constant() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert!(instruction.b_is_constant());
@ -807,10 +761,8 @@ mod tests {
fn decode_c_is_constant() {
let instruction = Instruction::add(
42,
Operand::Register(2),
TypeCode::STRING,
Operand::Constant(4),
TypeCode::CHARACTER,
Operand::Register(2, TypeCode::STRING),
Operand::Constant(4, TypeCode::CHARACTER),
);
assert!(instruction.c_is_constant());
@ -820,10 +772,8 @@ mod tests {
fn decode_b_type() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(TypeCode::STRING, instruction.b_type());
@ -833,10 +783,8 @@ mod tests {
fn decode_c_type() {
let instruction = Instruction::add(
42,
Operand::Constant(4),
TypeCode::STRING,
Operand::Register(2),
TypeCode::CHARACTER,
Operand::Constant(4, TypeCode::STRING),
Operand::Register(2, TypeCode::CHARACTER),
);
assert_eq!(TypeCode::CHARACTER, instruction.c_type());

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Modulo {
pub destination: u16,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Modulo {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Modulo {
destination,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Modulo> for Instruction {
let a_field = modulo.destination;
let (b_field, b_is_constant) = modulo.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = modulo.right.as_index_and_constant_flag();
let b_type = modulo.left_type;
let c_type = modulo.right_type;
let b_type = modulo.left.as_type();
let c_type = modulo.right.as_type();
InstructionFields {
operation,
@ -56,11 +50,19 @@ impl Display for Modulo {
let Modulo {
destination,
left,
left_type: _,
right,
right_type: _,
} = self;
write!(f, "R{destination} = {left} % {right}",)
match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
_ => todo!(),
}
write!(f, " = {left} % {right}",)
}
}

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Multiply {
pub destination: u16,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Multiply {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Multiply {
destination,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Multiply> for Instruction {
let a_field = multiply.destination;
let (b_field, b_is_constant) = multiply.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = multiply.right.as_index_and_constant_flag();
let b_type = multiply.left_type;
let c_type = multiply.right_type;
let b_type = multiply.left.as_type();
let c_type = multiply.right.as_type();
InstructionFields {
operation,
@ -56,11 +50,19 @@ impl Display for Multiply {
let Multiply {
destination,
left,
left_type: _,
right,
right_type: _,
} = self;
write!(f, "R{destination} = {left} ✕ {right}",)
match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
_ => todo!(),
}
write!(f, " = {left} ✕ {right}",)
}
}

View File

@ -7,7 +7,6 @@ use super::{InstructionFields, Operand, TypeCode};
pub struct Point {
pub destination: u16,
pub to: Operand,
pub r#type: TypeCode,
}
impl From<Instruction> for Point {
@ -15,7 +14,6 @@ impl From<Instruction> for Point {
Point {
destination: instruction.a_field(),
to: instruction.b_as_operand(),
r#type: instruction.b_type(),
}
}
}
@ -25,7 +23,7 @@ impl From<Point> for Instruction {
let operation = Operation::POINT;
let a_field = r#move.destination;
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag();
let b_type = r#move.r#type;
let b_type = r#move.to.as_type();
InstructionFields {
operation,
@ -41,13 +39,9 @@ impl From<Point> for Instruction {
impl Display for Point {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let Point {
destination,
to,
r#type,
} = self;
let Point { destination, to } = self;
match *r#type {
match to.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> R_BOOL_{to}"),
TypeCode::BYTE => write!(f, "R_BYTE_{destination} -> R_BYTE_{to}"),
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} -> R_CHAR_{to}"),

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Subtract {
pub destination: u16,
pub left: Operand,
pub left_type: TypeCode,
pub right: Operand,
pub right_type: TypeCode,
}
impl From<Instruction> for Subtract {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Subtract {
destination,
left,
left_type,
right,
right_type,
}
}
}
@ -33,8 +27,8 @@ impl From<Subtract> for Instruction {
let a_field = subtract.destination;
let (b_field, b_is_constant) = subtract.left.as_index_and_constant_flag();
let (c_field, c_is_constant) = subtract.right.as_index_and_constant_flag();
let b_type = subtract.left_type;
let c_type = subtract.right_type;
let b_type = subtract.left.as_type();
let c_type = subtract.right.as_type();
InstructionFields {
operation,
@ -56,11 +50,19 @@ impl Display for Subtract {
let Subtract {
destination,
left,
left_type: _,
right,
right_type: _,
} = self;
write!(f, "R{destination} = {left} - {right}",)
match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
TypeCode::CHARACTER => write!(f, "R_STR_{destination}")?,
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
_ => todo!(),
}
write!(f, " = {left} - {right}",)
}
}

View File

@ -1,6 +1,6 @@
use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
pub struct TypeCode(pub u8);
impl TypeCode {
@ -11,6 +11,8 @@ impl TypeCode {
pub const FLOAT: TypeCode = TypeCode(4);
pub const INTEGER: TypeCode = TypeCode(5);
pub const STRING: TypeCode = TypeCode(6);
pub const LIST: TypeCode = TypeCode(7);
pub const FUNCTION: TypeCode = TypeCode(8);
pub fn panic_from_unknown_code(self) -> ! {
panic!("Unknown type code: {}", self.0);