Compare commits

...

3 Commits

Author SHA1 Message Date
Jesse Brault
fa13697596 Instruction generation and implementation for shift and bitwise operators. 2026-03-15 16:18:09 -05:00
Jesse Brault
7e72037d9e Instruction generation and implementation for multiplicative operators. 2026-03-15 15:50:02 -05:00
Jesse Brault
b0660c9e5a Parsing and lexing bitwise operators. 2026-03-15 15:05:00 -05:00
11 changed files with 645 additions and 58 deletions

View File

@ -23,6 +23,9 @@ pub enum BinaryOperation {
Subtract, Subtract,
LeftShift, LeftShift,
RightShift, RightShift,
BitwiseAnd,
BitwiseXor,
BitwiseOr,
} }
pub struct BinaryExpression { pub struct BinaryExpression {
@ -135,13 +138,37 @@ impl BinaryExpression {
match &self.op { match &self.op {
BinaryOperation::Multiply => { BinaryOperation::Multiply => {
todo!() handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_multiply(rhs),
|lhs, rhs| lhs.multiply_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot multiply {} by {}",
lhs, rhs
)
),
diagnostics
);
} }
BinaryOperation::Divide => { BinaryOperation::Divide => {
todo!() handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_divide(rhs),
|lhs, rhs| lhs.divide_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs)
),
diagnostics
);
} }
BinaryOperation::Modulo => { BinaryOperation::Modulo => {
todo!() handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_modulo(rhs),
|lhs, rhs| lhs.modulo_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs)
),
diagnostics
);
} }
BinaryOperation::Add => { BinaryOperation::Add => {
handle_diagnostic!( handle_diagnostic!(
@ -166,8 +193,66 @@ impl BinaryExpression {
diagnostics diagnostics
) )
} }
BinaryOperation::LeftShift => todo!(), BinaryOperation::LeftShift => {
BinaryOperation::RightShift => todo!(), handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_left_shift(rhs),
|lhs, rhs| lhs.left_shift_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot left shift {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::RightShift => {
handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_right_shift(rhs),
|lhs, rhs| lhs.right_shift_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot right shift {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::BitwiseAnd => {
handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_bitwise_and(rhs),
|lhs, rhs| lhs.bitwise_and_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot bitwise and {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::BitwiseXor => handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_bitwise_xor(rhs),
|lhs, rhs| lhs.bitwise_xor_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot bitwise xor {} by {}", lhs, rhs)
),
diagnostics
),
BinaryOperation::BitwiseOr => {
handle_diagnostic!(
self.check_op(
|lhs, rhs| lhs.can_bitwise_or(rhs),
|lhs, rhs| lhs.bitwise_or_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot bitwise or {} by {}",
lhs, rhs
)
),
diagnostics
);
}
} }
diagnostics_result!(diagnostics) diagnostics_result!(diagnostics)
@ -191,13 +276,26 @@ impl BinaryExpression {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply) IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply)
} }
BinaryOperation::Divide => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Divide), BinaryOperation::Divide => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Divide),
BinaryOperation::Modulo => todo!(), BinaryOperation::Modulo => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Modulo),
BinaryOperation::Add => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Add), BinaryOperation::Add => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Add),
BinaryOperation::Subtract => { BinaryOperation::Subtract => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract) IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract)
} }
BinaryOperation::LeftShift => todo!(), BinaryOperation::LeftShift => {
BinaryOperation::RightShift => todo!(), IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::LeftShift)
}
BinaryOperation::RightShift => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::RightShift)
}
BinaryOperation::BitwiseAnd => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseAnd)
}
BinaryOperation::BitwiseXor => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseXor)
}
BinaryOperation::BitwiseOr => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseOr)
}
}; };
IrOperation::Binary(ir_binary_operation) IrOperation::Binary(ir_binary_operation)
} }

View File

@ -10,8 +10,14 @@ use std::fmt::{Display, Formatter};
pub enum IrBinaryOperator { pub enum IrBinaryOperator {
Multiply, Multiply,
Divide, Divide,
Modulo,
Add, Add,
Subtract, Subtract,
LeftShift,
RightShift,
BitwiseAnd,
BitwiseXor,
BitwiseOr,
} }
pub struct IrBinaryOperation { pub struct IrBinaryOperation {
@ -41,9 +47,16 @@ impl IrBinaryOperation {
self.right.multiply_operand(), self.right.multiply_operand(),
destination, destination,
), ),
IrBinaryOperator::Divide => { IrBinaryOperator::Divide => Instruction::Divide(
todo!() self.left.as_location_or_number(),
} self.right.as_location_or_number(),
destination,
),
IrBinaryOperator::Modulo => Instruction::Modulo(
self.left.as_location_or_number(),
self.right.as_location_or_number(),
destination,
),
IrBinaryOperator::Add => Instruction::Add( IrBinaryOperator::Add => Instruction::Add(
self.left.add_operand(constants_table), self.left.add_operand(constants_table),
self.right.add_operand(constants_table), self.right.add_operand(constants_table),
@ -54,6 +67,31 @@ impl IrBinaryOperation {
self.right.subtract_operand(), self.right.subtract_operand(),
destination, destination,
), ),
IrBinaryOperator::LeftShift => Instruction::LeftShift(
self.left.as_location_or_integer(),
self.right.as_location_or_integer(),
destination,
),
IrBinaryOperator::RightShift => Instruction::RightShift(
self.left.as_location_or_integer(),
self.right.as_location_or_integer(),
destination,
),
IrBinaryOperator::BitwiseAnd => Instruction::BitwiseAnd(
self.left.as_location_or_integer(),
self.right.as_location_or_integer(),
destination,
),
IrBinaryOperator::BitwiseXor => Instruction::BitwiseXor(
self.left.as_location_or_integer(),
self.right.as_location_or_integer(),
destination,
),
IrBinaryOperator::BitwiseOr => Instruction::BitwiseOr(
self.left.as_location_or_integer(),
self.right.as_location_or_integer(),
destination,
),
}; };
builder.push(instruction); builder.push(instruction);
} }
@ -68,12 +106,30 @@ impl Display for IrBinaryOperation {
IrBinaryOperator::Divide => { IrBinaryOperator::Divide => {
write!(f, "{} / {}", self.left, self.right) write!(f, "{} / {}", self.left, self.right)
} }
IrBinaryOperator::Modulo => {
write!(f, "{} % {}", self.left, self.right)
}
IrBinaryOperator::Add => { IrBinaryOperator::Add => {
write!(f, "{} + {}", self.left, self.right) write!(f, "{} + {}", self.left, self.right)
} }
IrBinaryOperator::Subtract => { IrBinaryOperator::Subtract => {
write!(f, "{} - {}", self.left, self.right) write!(f, "{} - {}", self.left, self.right)
} }
IrBinaryOperator::LeftShift => {
write!(f, "{} << {}", self.left, self.right)
}
IrBinaryOperator::RightShift => {
write!(f, "{} >> {}", self.left, self.right)
}
IrBinaryOperator::BitwiseAnd => {
write!(f, "{} & {}", self.left, self.right)
}
IrBinaryOperator::BitwiseXor => {
write!(f, "{} ^ {}", self.left, self.right)
}
IrBinaryOperator::BitwiseOr => {
write!(f, "{} | {}", self.left, self.right)
}
} }
} }
} }

View File

@ -4,8 +4,8 @@ use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescr
use crate::ir::register_allocation::VrUser; use crate::ir::register_allocation::VrUser;
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use dvm_lib::instruction::{ use dvm_lib::instruction::{
AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, AddOperand, Location, LocationOrInteger, LocationOrNumber, MoveOperand, MultiplyOperand,
SetFieldOperand, SubtractOperand, PushOperand, ReturnOperand, SetFieldOperand, SubtractOperand,
}; };
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashSet; use std::collections::HashSet;
@ -204,6 +204,33 @@ impl IrExpression {
} }
} }
} }
pub fn as_location_or_number(&self) -> LocationOrNumber {
match self {
IrExpression::Parameter(ir_parameter) => {
LocationOrNumber::Location(ir_parameter.as_location())
}
IrExpression::Variable(ir_variable) => {
LocationOrNumber::Location(ir_variable.borrow().descriptor().as_location())
}
IrExpression::Int(i) => LocationOrNumber::Int(*i),
IrExpression::Double(d) => LocationOrNumber::Double(*d),
_ => panic!("Attempt to convert {} to a location or number", self),
}
}
pub fn as_location_or_integer(&self) -> LocationOrInteger {
match self {
IrExpression::Parameter(ir_parameter) => {
LocationOrInteger::Location(ir_parameter.as_location())
}
IrExpression::Variable(ir_variable) => {
LocationOrInteger::Location(ir_variable.borrow().descriptor().as_location())
}
IrExpression::Int(i) => LocationOrInteger::Int(*i),
_ => panic!("Attempt to convert {} to a location or integer", self),
}
}
} }
impl Display for IrExpression { impl Display for IrExpression {
@ -233,13 +260,7 @@ impl VrUser for IrExpression {
match self { match self {
IrExpression::Parameter(_) => HashSet::new(), IrExpression::Parameter(_) => HashSet::new(),
IrExpression::Variable(ir_variable) => { IrExpression::Variable(ir_variable) => {
if let IrVariableDescriptor::VirtualRegister(vr_variable) = ir_variable.borrow().descriptor().vr_variable_descriptors()
ir_variable.borrow().descriptor()
{
HashSet::from([vr_variable.clone()])
} else {
HashSet::new()
}
} }
IrExpression::Int(_) => HashSet::new(), IrExpression::Int(_) => HashSet::new(),
IrExpression::Double(_) => HashSet::new(), IrExpression::Double(_) => HashSet::new(),

View File

@ -1,4 +1,5 @@
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use dvm_lib::instruction::Location;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;
@ -24,6 +25,10 @@ impl IrParameter {
pub fn stack_offset(&self) -> isize { pub fn stack_offset(&self) -> isize {
self.stack_offset self.stack_offset
} }
pub fn as_location(&self) -> Location {
Location::StackFrameOffset(self.stack_offset)
}
} }
impl Display for IrParameter { impl Display for IrParameter {

View File

@ -58,6 +58,12 @@ impl<'a> Lexer<'a> {
Token::new(self.position, self.position + 2, TokenKind::LeftShift) Token::new(self.position, self.position + 2, TokenKind::LeftShift)
} else if chunk.starts_with(">>") { } else if chunk.starts_with(">>") {
Token::new(self.position, self.position + 2, TokenKind::RightShift) Token::new(self.position, self.position + 2, TokenKind::RightShift)
} else if chunk.starts_with("&") {
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
} else if chunk.starts_with("^") {
Token::new(self.position, self.position + 1, TokenKind::Caret)
} else if chunk.starts_with("|") {
Token::new(self.position, self.position + 1, TokenKind::Bar)
} else if chunk.starts_with("=") { } else if chunk.starts_with("=") {
Token::new(self.position, self.position + 1, TokenKind::Equals) Token::new(self.position, self.position + 1, TokenKind::Equals)
} else if chunk.starts_with(",") { } else if chunk.starts_with(",") {

View File

@ -662,7 +662,58 @@ impl<'a> Parser<'a> {
} }
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> { fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
self.shift_expression() self.bitwise_or_expression()
}
fn bitwise_or_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.bitwise_xor_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Bar) {
self.advance(); // |
let rhs = self.bitwise_xor_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::BitwiseOr,
source_range,
));
}
Ok(result)
}
fn bitwise_xor_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.bitwise_and_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Caret) {
self.advance(); // ^
let rhs = self.bitwise_and_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::BitwiseXor,
source_range,
));
}
Ok(result)
}
fn bitwise_and_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
let mut result = self.shift_expression()?;
while self.current.is_some() && self.peek_current(TokenKind::Ampersand) {
self.advance(); // &
let rhs = self.shift_expression()?;
let source_range =
SourceRange::new(result.source_range().start(), rhs.source_range().end());
result = Expression::Binary(BinaryExpression::new(
result,
rhs,
BinaryOperation::BitwiseAnd,
source_range,
));
}
Ok(result)
} }
fn shift_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> { fn shift_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
@ -1067,6 +1118,32 @@ mod smoke_tests {
fn simple_right_shift() { fn simple_right_shift() {
smoke_test("fn main() 4 >> 1 end"); smoke_test("fn main() 4 >> 1 end");
} }
#[test]
fn simple_bitwise_and() {
smoke_test("fn main() 2 & 1 end");
}
#[test]
fn simple_bitwise_xor() {
smoke_test("fn main() 1 ^ 2 end");
}
#[test]
fn simple_bitwise_or() {
smoke_test("fn main() 1 | 2 end");
}
#[test]
fn ops_left_to_right() {
smoke_test(
"
fn main()
1 | 2 ^ 3 & 4 << 5 >> 7 + 8 - 9 * 10 / 11 % 12
end
",
)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -47,6 +47,9 @@ pub enum TokenKind {
Modulo, Modulo,
LeftShift, LeftShift,
RightShift, RightShift,
Ampersand,
Caret,
Bar,
Class, Class,
Dot, Dot,
SelfKw, SelfKw,

View File

@ -40,6 +40,14 @@ impl Display for TypeInfo {
} }
} }
fn is_number(type_info: &TypeInfo) -> bool {
matches!(type_info, TypeInfo::Integer | TypeInfo::Double)
}
fn are_numbers(left: &TypeInfo, right: &TypeInfo) -> bool {
is_number(left) && is_number(right)
}
impl TypeInfo { impl TypeInfo {
pub fn from_declared_name( pub fn from_declared_name(
declared_name: &str, declared_name: &str,
@ -93,6 +101,61 @@ impl TypeInfo {
} }
} }
pub fn can_negate(&self) -> bool {
is_number(self)
}
pub fn negate_result(&self) -> TypeInfo {
match self {
TypeInfo::Integer => TypeInfo::Integer,
TypeInfo::Double => TypeInfo::Double,
_ => panic!(),
}
}
pub fn can_multiply(&self, rhs: &Self) -> bool {
are_numbers(self, rhs)
}
pub fn multiply_result(&self, rhs: &Self) -> TypeInfo {
match self {
TypeInfo::Integer => match rhs {
TypeInfo::Integer => TypeInfo::Integer,
TypeInfo::Double => TypeInfo::Double,
_ => panic!(),
},
TypeInfo::Double => TypeInfo::Double,
_ => panic!(),
}
}
pub fn can_divide(&self, rhs: &Self) -> bool {
are_numbers(self, rhs)
}
pub fn divide_result(&self, _rhs: &Self) -> TypeInfo {
TypeInfo::Double // ok for now
}
pub fn can_modulo(&self, rhs: &Self) -> bool {
are_numbers(self, rhs)
}
pub fn modulo_result(&self, rhs: &Self) -> TypeInfo {
match self {
TypeInfo::Integer => match rhs {
TypeInfo::Integer => TypeInfo::Integer,
TypeInfo::Double => TypeInfo::Double,
_ => panic!(),
},
TypeInfo::Double => match rhs {
TypeInfo::Integer | TypeInfo::Double => TypeInfo::Double,
_ => panic!(),
},
_ => panic!(),
}
}
pub fn can_add(&self, rhs: &Self) -> bool { pub fn can_add(&self, rhs: &Self) -> bool {
match self { match self {
TypeInfo::Integer => { TypeInfo::Integer => {
@ -127,15 +190,7 @@ impl TypeInfo {
} }
pub fn can_subtract(&self, rhs: &Self) -> bool { pub fn can_subtract(&self, rhs: &Self) -> bool {
match self { are_numbers(self, rhs)
TypeInfo::Integer => {
matches!(rhs, TypeInfo::Integer | TypeInfo::Double)
}
TypeInfo::Double => {
matches!(rhs, TypeInfo::Integer | TypeInfo::Double)
}
_ => false,
}
} }
pub fn subtract_result(&self, rhs: &Self) -> TypeInfo { pub fn subtract_result(&self, rhs: &Self) -> TypeInfo {
@ -153,15 +208,43 @@ impl TypeInfo {
} }
} }
pub fn can_negate(&self) -> bool { pub fn can_left_shift(&self, rhs: &Self) -> bool {
matches!(self, TypeInfo::Integer | TypeInfo::Double) matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
} }
pub fn negate_result(&self) -> TypeInfo { pub fn left_shift_result(&self, _rhs: &Self) -> TypeInfo {
match self { TypeInfo::Integer
TypeInfo::Integer => TypeInfo::Integer, }
TypeInfo::Double => TypeInfo::Double,
_ => panic!(), pub fn can_right_shift(&self, rhs: &Self) -> bool {
} matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
}
pub fn right_shift_result(&self, _rhs: &Self) -> TypeInfo {
TypeInfo::Integer
}
pub fn can_bitwise_and(&self, rhs: &Self) -> bool {
matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
}
pub fn bitwise_and_result(&self, _rhs: &Self) -> TypeInfo {
TypeInfo::Integer
}
pub fn can_bitwise_xor(&self, rhs: &Self) -> bool {
matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
}
pub fn bitwise_xor_result(&self, _rhs: &Self) -> TypeInfo {
TypeInfo::Integer
}
pub fn can_bitwise_or(&self, rhs: &Self) -> bool {
matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
}
pub fn bitwise_or_result(&self, _rhs: &Self) -> TypeInfo {
TypeInfo::Integer
} }
} }

View File

@ -31,9 +31,19 @@ pub enum Instruction {
/// (field_pointer_mut_location, operand) /// (field_pointer_mut_location, operand)
SetField(Location, SetFieldOperand), SetField(Location, SetFieldOperand),
Multiply(MultiplyOperand, MultiplyOperand, Location),
Divide(LocationOrNumber, LocationOrNumber, Location),
Modulo(LocationOrNumber, LocationOrNumber, Location),
Add(AddOperand, AddOperand, Location), Add(AddOperand, AddOperand, Location),
Subtract(SubtractOperand, SubtractOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location),
Multiply(MultiplyOperand, MultiplyOperand, Location),
LeftShift(LocationOrInteger, LocationOrInteger, Location),
RightShift(LocationOrInteger, LocationOrInteger, Location),
BitwiseAnd(LocationOrInteger, LocationOrInteger, Location),
BitwiseXor(LocationOrInteger, LocationOrInteger, Location),
BitwiseOr(LocationOrInteger, LocationOrInteger, Location),
Pop(Option<Location>), Pop(Option<Location>),
@ -65,15 +75,41 @@ impl Display for Instruction {
write!(f, "pop") write!(f, "pop")
} }
} }
Instruction::Multiply(left, right, destination) => {
write!(f, "mul {}, {}, {}", left, right, destination)
}
Instruction::Divide(left, right, destination) => {
write!(f, "div {}, {}, {}", left, right, destination)
}
Instruction::Modulo(left, right, destination) => {
write!(f, "mod {}, {}, {}", left, right, destination)
}
Instruction::Add(left, right, destination) => { Instruction::Add(left, right, destination) => {
write!(f, "add {}, {}, {}", left, right, destination) write!(f, "add {}, {}, {}", left, right, destination)
} }
Instruction::Subtract(left, right, destination) => { Instruction::Subtract(left, right, destination) => {
write!(f, "sub {}, {}, {}", left, right, destination) write!(f, "sub {}, {}, {}", left, right, destination)
} }
Instruction::Multiply(left, right, destination) => {
write!(f, "mul {}, {}, {}", left, right, destination) Instruction::LeftShift(left, right, destination) => {
write!(f, "shl {}, {}, {}", left, right, destination)
} }
Instruction::RightShift(left, right, destination) => {
write!(f, "shr {}, {}, {}", left, right, destination)
}
Instruction::BitwiseAnd(left, right, destination) => {
write!(f, "and {}, {}, {}", left, right, destination)
}
Instruction::BitwiseXor(left, right, destination) => {
write!(f, "xor {}, {}, {}", left, right, destination)
}
Instruction::BitwiseOr(left, right, destination) => {
write!(f, "or {}, {}, {}", left, right, destination)
}
Instruction::SetReturnValue(source) => { Instruction::SetReturnValue(source) => {
write!(f, "srv {}", source) write!(f, "srv {}", source)
} }
@ -102,7 +138,7 @@ impl Display for Instruction {
write!(f, "readf *{}, {}", field_pointer_location, destination) write!(f, "readf *{}, {}", field_pointer_location, destination)
} }
Instruction::SetField(self_location, destination) => { Instruction::SetField(self_location, destination) => {
write!(f, "setf {}, {}", self_location, destination) write!(f, "setf *{}, {}", self_location, destination)
} }
} }
} }
@ -130,6 +166,46 @@ impl Display for Location {
} }
} }
pub enum LocationOrNumber {
Location(Location),
Int(i32),
Double(f64),
}
impl Display for LocationOrNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LocationOrNumber::Location(location) => {
write!(f, "{}", location)
}
LocationOrNumber::Int(i) => {
write!(f, "{}", i)
}
LocationOrNumber::Double(d) => {
write!(f, "{}", d)
}
}
}
}
pub enum LocationOrInteger {
Location(Location),
Int(i32),
}
impl Display for LocationOrInteger {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LocationOrInteger::Location(location) => {
write!(f, "{}", location)
}
LocationOrInteger::Int(i) => {
write!(f, "{}", i)
}
}
}
}
pub enum MoveOperand { pub enum MoveOperand {
Location(Location), Location(Location),
Int(i32), Int(i32),

View File

@ -6,7 +6,8 @@ use crate::vm::function::Function;
use crate::vm::object::get_object; use crate::vm::object::get_object;
use crate::vm::operand::Operand; use crate::vm::operand::Operand;
use crate::vm::operand_helpers::{ use crate::vm::operand_helpers::{
add_operand_to_value, move_operand_to_value, multiply_operand_to_value, push_operand_to_value, add_operand_to_value, location_or_integer_to_value, location_or_number_to_value,
move_operand_to_value, multiply_operand_to_value, push_operand_to_value,
return_operand_to_value, set_field_operand_to_value, subtract_operand_to_value, return_operand_to_value, set_field_operand_to_value, subtract_operand_to_value,
}; };
use crate::vm::util::*; use crate::vm::util::*;
@ -419,6 +420,72 @@ pub fn call<'a>(
call_stack.top_mut().increment_ip(); call_stack.top_mut().increment_ip();
} }
/* Multiplicative instructions */
Instruction::Multiply(left_operand, right_operand, destination) => {
let left_value =
multiply_operand_to_value(left_operand, registers, call_stack.top());
let right_value =
multiply_operand_to_value(right_operand, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li * ri),
Value::Double(rd) => Value::Double(li as f64 * rd),
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
},
Value::Double(ld) => match right_value {
Value::Int(ri) => Value::Double(ld * ri as f64),
Value::Double(rd) => Value::Double(ld * rd),
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
},
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
Instruction::Divide(left, right, destination) => {
let left_value = location_or_number_to_value(left, registers, call_stack.top());
let right_value = location_or_number_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Double(li as f64 / ri as f64),
Value::Double(rd) => Value::Double(li as f64 / rd),
_ => panic!("Attempt to divide {:?} and {:?}", left_value, right_value),
},
Value::Double(ld) => match right_value {
Value::Int(ri) => Value::Double(ld / ri as f64),
Value::Double(rd) => Value::Double(ld / rd),
_ => panic!("Attempt to divide {:?} and {:?}", left_value, right_value),
},
_ => panic!("Attempt to divide {:?} and {:?}", left_value, right_value),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
Instruction::Modulo(left, right, destination) => {
let left_value = location_or_number_to_value(left, registers, call_stack.top());
let right_value = location_or_number_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li % ri),
Value::Double(rd) => Value::Double(li as f64 % rd),
_ => panic!("Attempt to modulo {:?} and {:?}", left_value, right_value),
},
Value::Double(ld) => match right_value {
Value::Int(ri) => Value::Double(ld % ri as f64),
Value::Double(rd) => Value::Double(ld % rd),
_ => panic!("Attempt to modulo {:?} and {:?}", left_value, right_value),
},
_ => panic!("Attempt to modulo {:?} and {:?}", left_value, right_value),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
/* Add instructions */ /* Add instructions */
Instruction::Add(left_operand, right_operand, destination) => { Instruction::Add(left_operand, right_operand, destination) => {
let left_value = add_operand_to_value( let left_value = add_operand_to_value(
@ -492,24 +559,86 @@ pub fn call<'a>(
put_value(registers, call_stack.top_mut(), destination, result); put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip(); call_stack.top_mut().increment_ip();
} }
Instruction::Multiply(left_operand, right_operand, destination) => {
let left_value = /* Shift instructions */
multiply_operand_to_value(left_operand, registers, call_stack.top()); Instruction::LeftShift(left, right, destination) => {
let right_value = let left_value = location_or_integer_to_value(left, registers, call_stack.top());
multiply_operand_to_value(right_operand, registers, call_stack.top()); let right_value = location_or_integer_to_value(right, registers, call_stack.top());
let result = match left_value { let result = match left_value {
Value::Int(li) => match right_value { Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li * ri), Value::Int(ri) => Value::Int(li << ri),
Value::Double(rd) => Value::Double(li as f64 * rd), _ => panic!("Attempt to left shift {} by {}", left, right),
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
}, },
Value::Double(ld) => match right_value { _ => panic!("Attempt to left shift {} by {}", left_value, right_value),
Value::Int(ri) => Value::Double(ld * ri as f64), };
Value::Double(rd) => Value::Double(ld * rd),
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value), put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
Instruction::RightShift(left, right, destination) => {
let left_value = location_or_integer_to_value(left, registers, call_stack.top());
let right_value = location_or_integer_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li >> ri),
_ => panic!("Attempt to right shift {} by {}", left_value, right_value),
}, },
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value), _ => panic!("Attempt to right shift {} by {}", left_value, right_value),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
/* Bitwise instructions */
Instruction::BitwiseAnd(left, right, destination) => {
let left_value = location_or_integer_to_value(left, registers, call_stack.top());
let right_value = location_or_integer_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li & ri),
_ => panic!("Attempt to bitwise and {} by {}", left_value, right_value),
},
_ => panic!("Attempt to bitwise and {} by {}", left_value, right_value),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
Instruction::BitwiseXor(left, right, destination) => {
let left_value = location_or_integer_to_value(left, registers, call_stack.top());
let right_value = location_or_integer_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li ^ ri),
_ => panic!("Attempt to bitwise xor {} by {}", left_value, right_value),
},
_ => panic!(
"Attempt to left bitwise xor {} by {}",
left_value, right_value
),
};
put_value(registers, call_stack.top_mut(), destination, result);
call_stack.top_mut().increment_ip();
}
Instruction::BitwiseOr(left, right, destination) => {
let left_value = location_or_integer_to_value(left, registers, call_stack.top());
let right_value = location_or_integer_to_value(right, registers, call_stack.top());
let result = match left_value {
Value::Int(li) => match right_value {
Value::Int(ri) => Value::Int(li | ri),
_ => panic!("Attempt to bitwise or {} by {}", left_value, right_value),
},
_ => panic!(
"Attempt to left bitwise or {} by {}",
left_value, right_value
),
}; };
put_value(registers, call_stack.top_mut(), destination, result); put_value(registers, call_stack.top_mut(), destination, result);

View File

@ -1,6 +1,6 @@
use crate::instruction::{ use crate::instruction::{
AddOperand, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SetFieldOperand, AddOperand, LocationOrInteger, LocationOrNumber, MoveOperand, MultiplyOperand, PushOperand,
SubtractOperand, ReturnOperand, SetFieldOperand, SubtractOperand,
}; };
use crate::vm::CallFrame; use crate::vm::CallFrame;
use crate::vm::constant::Constant; use crate::vm::constant::Constant;
@ -138,3 +138,36 @@ pub fn set_field_operand_to_value(
SetFieldOperand::String(constant_name) => load_constant_value(constants, constant_name), SetFieldOperand::String(constant_name) => load_constant_value(constants, constant_name),
} }
} }
pub fn location_or_number_to_value(
location_or_number: &LocationOrNumber,
registers: &[Operand],
current_frame: &CallFrame,
) -> Value {
match location_or_number {
LocationOrNumber::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
LocationOrNumber::Int(i) => Value::Int(*i),
LocationOrNumber::Double(d) => Value::Double(*d),
}
}
pub fn location_or_integer_to_value(
location_or_integer: &LocationOrInteger,
registers: &[Operand],
current_frame: &CallFrame,
) -> Value {
match location_or_integer {
LocationOrInteger::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
LocationOrInteger::Int(i) => Value::Int(*i),
}
}