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) = let (previous_instruction, previous_type, previous_position) =
self.instructions.pop().unwrap(); 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 { if push_back {
self.instructions.push(( self.instructions.push((
@ -832,48 +832,10 @@ impl<'src> Compiler<'src> {
Ok(()) Ok(())
} }
fn handle_binary_argument( fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
&mut self, let (argument, push_back) = (instruction.as_operand(), !instruction.yields_value());
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());
if function.returns_value() { (argument, push_back)
(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))
} }
fn parse_math_binary(&mut self) -> Result<(), CompileError> { fn parse_math_binary(&mut self) -> Result<(), CompileError> {
@ -884,7 +846,7 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: self.previous_position, 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 left_is_mutable_local = if left_instruction.operation() == Operation::POINT {
let Point { to, .. } = Point::from(left_instruction); let Point { to, .. } = Point::from(left_instruction);
@ -915,13 +877,13 @@ impl<'src> Compiler<'src> {
check_math_type(&left_type, operator, &left_position)?; check_math_type(&left_type, operator, &left_position)?;
let (left_type_code, destination) = match left_type { let destination = match left_type {
Type::Boolean => (TypeCode::BOOLEAN, self.next_boolean_register()), Type::Boolean => self.next_boolean_register(),
Type::Byte => (TypeCode::BYTE, self.next_byte_register()), Type::Byte => self.next_byte_register(),
Type::Character => (TypeCode::CHARACTER, self.next_character_register()), Type::Character => self.next_character_register(),
Type::Float => (TypeCode::FLOAT, self.next_float_register()), Type::Float => self.next_float_register(),
Type::Integer => (TypeCode::INTEGER, self.next_integer_register()), Type::Integer => self.next_integer_register(),
Type::String => (TypeCode::STRING, self.next_string_register()), Type::String => self.next_string_register(),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -936,7 +898,7 @@ impl<'src> Compiler<'src> {
self.parse_sub_expression(&rule.precedence)?; self.parse_sub_expression(&rule.precedence)?;
let (right_instruction, right_type, right_position) = self.instructions.pop().unwrap(); 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_type(&right_type, operator, &right_position)?;
check_math_types( check_math_types(
@ -947,16 +909,6 @@ impl<'src> Compiler<'src> {
&right_position, &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 { if push_back_right {
self.instructions self.instructions
.push((right_instruction, right_type, right_position)); .push((right_instruction, right_type, right_position));
@ -970,21 +922,11 @@ impl<'src> Compiler<'src> {
left_type.clone() left_type.clone()
}; };
let instruction = match operator { let instruction = match operator {
Token::Plus | Token::PlusEqual => { Token::Plus | Token::PlusEqual => Instruction::add(destination, left, right),
Instruction::add(destination, left, left_type_code, right, right_type_code) Token::Minus | Token::MinusEqual => Instruction::subtract(destination, left, right),
} Token::Star | Token::StarEqual => Instruction::multiply(destination, left, right),
Token::Minus | Token::MinusEqual => { Token::Slash | Token::SlashEqual => Instruction::divide(destination, left, right),
Instruction::subtract(destination, left, left_type_code, right, right_type_code) Token::Percent | Token::PercentEqual => Instruction::modulo(destination, left, right),
}
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)
}
_ => { _ => {
return Err(CompileError::ExpectedTokenMultiple { return Err(CompileError::ExpectedTokenMultiple {
expected: &[ expected: &[
@ -1031,23 +973,13 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: self.previous_position, 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 = self.current_token;
let operator_position = self.current_position; let operator_position = self.current_position;
let rule = ParseRule::from(&operator); let rule = ParseRule::from(&operator);
// TODO: Check if the left type is a valid type for comparison // 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 { if push_back_left {
self.instructions self.instructions
.push((left_instruction, left_type, left_position)); .push((left_instruction, left_type, left_position));
@ -1063,21 +995,11 @@ impl<'src> Compiler<'src> {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: self.previous_position, 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 right type is a valid type for comparison
// TODO: Check if the left and right types are compatible // 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 { if push_back_right {
self.instructions self.instructions
.push((right_instruction, right_type, right_position)); .push((right_instruction, right_type, right_position));
@ -1085,22 +1007,12 @@ impl<'src> Compiler<'src> {
let destination = self.next_boolean_register(); let destination = self.next_boolean_register();
let comparison = match operator { let comparison = match operator {
Token::DoubleEqual => { Token::DoubleEqual => Instruction::equal(true, left, right),
Instruction::equal(true, left, left_type_code, right, right_type_code) Token::BangEqual => Instruction::equal(false, left, right),
} Token::Less => Instruction::less(true, left, right),
Token::BangEqual => { Token::LessEqual => Instruction::less_equal(true, left, right),
Instruction::equal(false, left, left_type_code, right, right_type_code) Token::Greater => Instruction::less_equal(false, left, right),
} Token::GreaterEqual => Instruction::less(false, left, right),
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)
}
_ => { _ => {
return Err(CompileError::ExpectedTokenMultiple { return Err(CompileError::ExpectedTokenMultiple {
expected: &[ expected: &[
@ -1289,8 +1201,7 @@ impl<'src> Compiler<'src> {
}; };
let point = Instruction::point( let point = Instruction::point(
local_register_index, local_register_index,
Operand::Register(register), Operand::Register(register, r#type.type_code()),
r#type.type_code(),
); );
self.emit_instruction(point, r#type, start_position); self.emit_instruction(point, r#type, start_position);
@ -1310,8 +1221,7 @@ impl<'src> Compiler<'src> {
}; };
let point = Instruction::point( let point = Instruction::point(
destination, destination,
Operand::Register(local_register_index), Operand::Register(local_register_index, r#type.type_code()),
r#type.type_code(),
); );
self.emit_instruction(point, r#type, self.previous_position); 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> { fn parse_implicit_return(&mut self) -> Result<(), CompileError> {
if matches!(self.get_last_operation(), Some(Operation::POINT)) { if matches!(self.get_last_operation(), Some(Operation::POINT)) {
let Point { let Point { destination, to } = Point::from(self.instructions.last().unwrap().0);
destination,
r#type: type_code,
..
} = Point::from(self.instructions.last().unwrap().0);
let (_, r#type, _) = self.instructions.pop().unwrap(); 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); self.emit_instruction(r#return, r#type, self.current_position);
} else if matches!(self.get_last_operation(), Some(Operation::RETURN)) } 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 struct Add {
pub destination: u16, pub destination: u16,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Add { impl From<Instruction> for Add {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Add { Add {
destination, destination,
left, left,
left_type,
right, right,
right_type,
} }
} }
} }
@ -33,8 +27,8 @@ impl From<Add> for Instruction {
let a_field = add.destination; let a_field = add.destination;
let (b_field, b_is_constant) = add.left.as_index_and_constant_flag(); 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 (c_field, c_is_constant) = add.right.as_index_and_constant_flag();
let b_type = add.left_type; let b_type = add.left.as_type();
let c_type = add.right_type; let c_type = add.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,15 +50,13 @@ impl Display for Add {
let Add { let Add {
destination, destination,
left, left,
left_type,
right, right,
right_type: _,
} = self; } = self;
match *left_type { match left.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?, TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
TypeCode::BYTE => write!(f, "R_BYTE_{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::FLOAT => write!(f, "R_FLOAT_{destination}")?,
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?, TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
TypeCode::STRING => write!(f, "R_STR_{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 struct Divide {
pub destination: u16, pub destination: u16,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Divide { impl From<Instruction> for Divide {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Divide { Divide {
destination, destination,
left, left,
left_type,
right, right,
right_type,
} }
} }
} }
@ -33,8 +27,8 @@ impl From<Divide> for Instruction {
let a_field = divide.destination; let a_field = divide.destination;
let (b_field, b_is_constant) = divide.left.as_index_and_constant_flag(); 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 (c_field, c_is_constant) = divide.right.as_index_and_constant_flag();
let b_type = divide.left_type; let b_type = divide.left.as_type();
let c_type = divide.right_type; let c_type = divide.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,11 +50,19 @@ impl Display for Divide {
let Divide { let Divide {
destination, destination,
left, left,
left_type: _,
right, right,
right_type: _,
} = self; } = 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 std::fmt::{self, Display, Formatter};
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode}; use super::{Instruction, InstructionFields, Operand, Operation};
pub struct Equal { pub struct Equal {
pub comparator: bool, pub comparator: bool,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Equal { impl From<Instruction> for Equal {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let comparator = instruction.d_field(); let comparator = instruction.d_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Equal { Equal {
comparator, comparator,
left, left,
left_type,
right, 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 (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 (c_field, c_is_constant) = equal_bool.right.as_index_and_constant_flag();
let d_field = equal_bool.comparator; let d_field = equal_bool.comparator;
let b_type = equal_bool.left_type; let b_type = equal_bool.left.as_type();
let c_type = equal_bool.right_type; let c_type = equal_bool.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,9 +50,7 @@ impl Display for Equal {
let Equal { let Equal {
comparator, comparator,
left, left,
left_type: _,
right, right,
right_type: _,
} = self; } = self;
let operator = if *comparator { "==" } else { "" }; let operator = if *comparator { "==" } else { "" };

View File

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

View File

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

View File

@ -278,12 +278,52 @@ impl Instruction {
*self = fields.build(); *self = fields.build();
} }
pub fn point(destination: u16, to: Operand, r#type: TypeCode) -> Instruction { pub fn as_operand(&self) -> Operand {
Instruction::from(Point { match self.operation() {
destination, Operation::POINT => {
to, let Point { destination, to } = Point::from(*self);
r#type,
}) 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 { pub fn close(from: u16, to: u16) -> Instruction {
@ -341,131 +381,67 @@ impl Instruction {
}) })
} }
pub fn add( pub fn add(destination: u16, left: Operand, right: Operand) -> Instruction {
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Add { Instruction::from(Add {
destination, destination,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn subtract( pub fn subtract(destination: u16, left: Operand, right: Operand) -> Instruction {
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Subtract { Instruction::from(Subtract {
destination, destination,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn multiply( pub fn multiply(destination: u16, left: Operand, right: Operand) -> Instruction {
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Multiply { Instruction::from(Multiply {
destination, destination,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn divide( pub fn divide(destination: u16, left: Operand, right: Operand) -> Instruction {
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Divide { Instruction::from(Divide {
destination, destination,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn modulo( pub fn modulo(destination: u16, left: Operand, right: Operand) -> Instruction {
destination: u16,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Modulo { Instruction::from(Modulo {
destination, destination,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn equal( pub fn equal(comparator: bool, left: Operand, right: Operand) -> Instruction {
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Equal { Instruction::from(Equal {
comparator, comparator,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn less( pub fn less(comparator: bool, left: Operand, right: Operand) -> Instruction {
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(Less { Instruction::from(Less {
comparator, comparator,
left, left,
left_type,
right, right,
right_type,
}) })
} }
pub fn less_equal( pub fn less_equal(comparator: bool, left: Operand, right: Operand) -> Instruction {
comparator: bool,
left: Operand,
left_type: TypeCode,
right: Operand,
right_type: TypeCode,
) -> Instruction {
Instruction::from(LessEqual { Instruction::from(LessEqual {
comparator, comparator,
left, left,
left_type,
right, right,
right_type,
}) })
} }
@ -552,55 +528,20 @@ impl Instruction {
self.operation().is_comparison() 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 { pub fn b_as_operand(&self) -> Operand {
if self.b_is_constant() { if self.b_is_constant() {
Operand::Constant(self.b_field()) Operand::Constant(self.b_field(), self.b_type())
} else { } else {
Operand::Register(self.b_field()) Operand::Register(self.b_field(), self.b_type())
} }
} }
pub fn b_and_c_as_operands(&self) -> (Operand, Operand) { pub fn b_and_c_as_operands(&self) -> (Operand, Operand) {
let left = if self.b_is_constant() { let left = self.b_as_operand();
Operand::Constant(self.b_field())
} else {
Operand::Register(self.b_field())
};
let right = if self.c_is_constant() { let right = if self.c_is_constant() {
Operand::Constant(self.c_field()) Operand::Constant(self.c_field(), self.c_type())
} else { } else {
Operand::Register(self.c_field()) Operand::Register(self.c_field(), self.c_type())
}; };
(left, right) (left, right)
@ -684,30 +625,37 @@ impl Display for Instruction {
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Operand { pub enum Operand {
Constant(u16), Constant(u16, TypeCode),
Register(u16), Register(u16, TypeCode),
} }
impl Operand { impl Operand {
pub fn index(&self) -> u16 { pub fn index(&self) -> u16 {
match self { match self {
Operand::Constant(index) => *index, Operand::Constant(index, _) => *index,
Operand::Register(index) => *index, Operand::Register(index, _) => *index,
} }
} }
pub fn is_constant(&self) -> bool { pub fn is_constant(&self) -> bool {
matches!(self, Operand::Constant(_)) matches!(self, Operand::Constant(_, _))
} }
pub fn is_register(&self) -> bool { pub fn is_register(&self) -> bool {
matches!(self, Operand::Register(_)) matches!(self, Operand::Register(_, _))
} }
pub fn as_index_and_constant_flag(&self) -> (u16, bool) { pub fn as_index_and_constant_flag(&self) -> (u16, bool) {
match self { match self {
Operand::Constant(index) => (*index, true), Operand::Constant(index, _) => (*index, true),
Operand::Register(index) => (*index, false), 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 { impl Display for Operand {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Operand::Constant(index) => write!(f, "{index}"), Operand::Constant(index, r#type) => match *r#type {
Operand::Register(index) => write!(f, "{index}"), 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() { fn decode_operation() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(instruction.operation(), Operation::ADD); assert_eq!(instruction.operation(), Operation::ADD);
@ -742,10 +706,8 @@ mod tests {
fn decode_a_field() { fn decode_a_field() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(42, instruction.a_field()); assert_eq!(42, instruction.a_field());
@ -755,10 +717,8 @@ mod tests {
fn decode_b_field() { fn decode_b_field() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(4, instruction.b_field()); assert_eq!(4, instruction.b_field());
@ -768,10 +728,8 @@ mod tests {
fn decode_c_field() { fn decode_c_field() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(2, instruction.c_field()); assert_eq!(2, instruction.c_field());
@ -781,10 +739,8 @@ mod tests {
fn decode_d_field() { fn decode_d_field() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert!(!instruction.d_field()); assert!(!instruction.d_field());
@ -794,10 +750,8 @@ mod tests {
fn decode_b_is_constant() { fn decode_b_is_constant() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert!(instruction.b_is_constant()); assert!(instruction.b_is_constant());
@ -807,10 +761,8 @@ mod tests {
fn decode_c_is_constant() { fn decode_c_is_constant() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Register(2), Operand::Register(2, TypeCode::STRING),
TypeCode::STRING, Operand::Constant(4, TypeCode::CHARACTER),
Operand::Constant(4),
TypeCode::CHARACTER,
); );
assert!(instruction.c_is_constant()); assert!(instruction.c_is_constant());
@ -820,10 +772,8 @@ mod tests {
fn decode_b_type() { fn decode_b_type() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(TypeCode::STRING, instruction.b_type()); assert_eq!(TypeCode::STRING, instruction.b_type());
@ -833,10 +783,8 @@ mod tests {
fn decode_c_type() { fn decode_c_type() {
let instruction = Instruction::add( let instruction = Instruction::add(
42, 42,
Operand::Constant(4), Operand::Constant(4, TypeCode::STRING),
TypeCode::STRING, Operand::Register(2, TypeCode::CHARACTER),
Operand::Register(2),
TypeCode::CHARACTER,
); );
assert_eq!(TypeCode::CHARACTER, instruction.c_type()); assert_eq!(TypeCode::CHARACTER, instruction.c_type());

View File

@ -5,24 +5,18 @@ use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
pub struct Modulo { pub struct Modulo {
pub destination: u16, pub destination: u16,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Modulo { impl From<Instruction> for Modulo {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Modulo { Modulo {
destination, destination,
left, left,
left_type,
right, right,
right_type,
} }
} }
} }
@ -33,8 +27,8 @@ impl From<Modulo> for Instruction {
let a_field = modulo.destination; let a_field = modulo.destination;
let (b_field, b_is_constant) = modulo.left.as_index_and_constant_flag(); 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 (c_field, c_is_constant) = modulo.right.as_index_and_constant_flag();
let b_type = modulo.left_type; let b_type = modulo.left.as_type();
let c_type = modulo.right_type; let c_type = modulo.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,11 +50,19 @@ impl Display for Modulo {
let Modulo { let Modulo {
destination, destination,
left, left,
left_type: _,
right, right,
right_type: _,
} = self; } = 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 struct Multiply {
pub destination: u16, pub destination: u16,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Multiply { impl From<Instruction> for Multiply {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Multiply { Multiply {
destination, destination,
left, left,
left_type,
right, right,
right_type,
} }
} }
} }
@ -33,8 +27,8 @@ impl From<Multiply> for Instruction {
let a_field = multiply.destination; let a_field = multiply.destination;
let (b_field, b_is_constant) = multiply.left.as_index_and_constant_flag(); 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 (c_field, c_is_constant) = multiply.right.as_index_and_constant_flag();
let b_type = multiply.left_type; let b_type = multiply.left.as_type();
let c_type = multiply.right_type; let c_type = multiply.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,11 +50,19 @@ impl Display for Multiply {
let Multiply { let Multiply {
destination, destination,
left, left,
left_type: _,
right, right,
right_type: _,
} = self; } = 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 struct Point {
pub destination: u16, pub destination: u16,
pub to: Operand, pub to: Operand,
pub r#type: TypeCode,
} }
impl From<Instruction> for Point { impl From<Instruction> for Point {
@ -15,7 +14,6 @@ impl From<Instruction> for Point {
Point { Point {
destination: instruction.a_field(), destination: instruction.a_field(),
to: instruction.b_as_operand(), to: instruction.b_as_operand(),
r#type: instruction.b_type(),
} }
} }
} }
@ -25,7 +23,7 @@ impl From<Point> for Instruction {
let operation = Operation::POINT; let operation = Operation::POINT;
let a_field = r#move.destination; let a_field = r#move.destination;
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag(); 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 { InstructionFields {
operation, operation,
@ -41,13 +39,9 @@ impl From<Point> for Instruction {
impl Display for Point { impl Display for Point {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let Point { let Point { destination, to } = self;
destination,
to,
r#type,
} = self;
match *r#type { match to.as_type() {
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> R_BOOL_{to}"), TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> R_BOOL_{to}"),
TypeCode::BYTE => write!(f, "R_BYTE_{destination} -> R_BYTE_{to}"), TypeCode::BYTE => write!(f, "R_BYTE_{destination} -> R_BYTE_{to}"),
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination} -> R_CHAR_{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 struct Subtract {
pub destination: u16, pub destination: u16,
pub left: Operand, pub left: Operand,
pub left_type: TypeCode,
pub right: Operand, pub right: Operand,
pub right_type: TypeCode,
} }
impl From<Instruction> for Subtract { impl From<Instruction> for Subtract {
fn from(instruction: Instruction) -> Self { fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();
let left_type = instruction.b_type();
let right_type = instruction.c_type();
Subtract { Subtract {
destination, destination,
left, left,
left_type,
right, right,
right_type,
} }
} }
} }
@ -33,8 +27,8 @@ impl From<Subtract> for Instruction {
let a_field = subtract.destination; let a_field = subtract.destination;
let (b_field, b_is_constant) = subtract.left.as_index_and_constant_flag(); 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 (c_field, c_is_constant) = subtract.right.as_index_and_constant_flag();
let b_type = subtract.left_type; let b_type = subtract.left.as_type();
let c_type = subtract.right_type; let c_type = subtract.right.as_type();
InstructionFields { InstructionFields {
operation, operation,
@ -56,11 +50,19 @@ impl Display for Subtract {
let Subtract { let Subtract {
destination, destination,
left, left,
left_type: _,
right, right,
right_type: _,
} = self; } = 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; use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
pub struct TypeCode(pub u8); pub struct TypeCode(pub u8);
impl TypeCode { impl TypeCode {
@ -11,6 +11,8 @@ impl TypeCode {
pub const FLOAT: TypeCode = TypeCode(4); pub const FLOAT: TypeCode = TypeCode(4);
pub const INTEGER: TypeCode = TypeCode(5); pub const INTEGER: TypeCode = TypeCode(5);
pub const STRING: TypeCode = TypeCode(6); 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) -> ! { pub fn panic_from_unknown_code(self) -> ! {
panic!("Unknown type code: {}", self.0); panic!("Unknown type code: {}", self.0);