diff --git a/dmc-lib/src/ast/binary_expression.rs b/dmc-lib/src/ast/binary_expression.rs index 5cae321..9619f02 100644 --- a/dmc-lib/src/ast/binary_expression.rs +++ b/dmc-lib/src/ast/binary_expression.rs @@ -138,13 +138,37 @@ impl BinaryExpression { match &self.op { 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 => { - 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 => { - 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 => { handle_diagnostic!( @@ -169,11 +193,66 @@ impl BinaryExpression { diagnostics ) } - BinaryOperation::LeftShift => todo!(), - BinaryOperation::RightShift => todo!(), - BinaryOperation::BitwiseAnd => todo!(), - BinaryOperation::BitwiseXor => todo!(), - BinaryOperation::BitwiseOr => todo!(), + BinaryOperation::LeftShift => { + 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) @@ -197,16 +276,26 @@ impl BinaryExpression { IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply) } 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::Subtract => { IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract) } - BinaryOperation::LeftShift => todo!(), - BinaryOperation::RightShift => todo!(), - BinaryOperation::BitwiseAnd => todo!(), - BinaryOperation::BitwiseXor => todo!(), - BinaryOperation::BitwiseOr => todo!(), + BinaryOperation::LeftShift => { + 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) } diff --git a/dmc-lib/src/ir/ir_binary_operation.rs b/dmc-lib/src/ir/ir_binary_operation.rs index 5d61c25..c12ecc1 100644 --- a/dmc-lib/src/ir/ir_binary_operation.rs +++ b/dmc-lib/src/ir/ir_binary_operation.rs @@ -10,8 +10,14 @@ use std::fmt::{Display, Formatter}; pub enum IrBinaryOperator { Multiply, Divide, + Modulo, Add, Subtract, + LeftShift, + RightShift, + BitwiseAnd, + BitwiseXor, + BitwiseOr, } pub struct IrBinaryOperation { @@ -41,9 +47,16 @@ impl IrBinaryOperation { self.right.multiply_operand(), destination, ), - IrBinaryOperator::Divide => { - todo!() - } + IrBinaryOperator::Divide => Instruction::Divide( + 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( self.left.add_operand(constants_table), self.right.add_operand(constants_table), @@ -54,6 +67,11 @@ impl IrBinaryOperation { self.right.subtract_operand(), destination, ), + IrBinaryOperator::LeftShift => todo!(), + IrBinaryOperator::RightShift => todo!(), + IrBinaryOperator::BitwiseAnd => todo!(), + IrBinaryOperator::BitwiseXor => todo!(), + IrBinaryOperator::BitwiseOr => todo!(), }; builder.push(instruction); } @@ -68,12 +86,30 @@ impl Display for IrBinaryOperation { IrBinaryOperator::Divide => { write!(f, "{} / {}", self.left, self.right) } + IrBinaryOperator::Modulo => { + write!(f, "{} % {}", self.left, self.right) + } IrBinaryOperator::Add => { write!(f, "{} + {}", self.left, self.right) } IrBinaryOperator::Subtract => { 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) + } } } } diff --git a/dmc-lib/src/ir/ir_expression.rs b/dmc-lib/src/ir/ir_expression.rs index bb94286..72d775d 100644 --- a/dmc-lib/src/ir/ir_expression.rs +++ b/dmc-lib/src/ir/ir_expression.rs @@ -4,8 +4,8 @@ use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescr use crate::ir::register_allocation::VrUser; use crate::type_info::TypeInfo; use dvm_lib::instruction::{ - AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, - SetFieldOperand, SubtractOperand, + AddOperand, Location, LocationOrNumber, MoveOperand, MultiplyOperand, PushOperand, + ReturnOperand, SetFieldOperand, SubtractOperand, }; use std::cell::RefCell; use std::collections::HashSet; @@ -204,6 +204,20 @@ 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), + } + } } impl Display for IrExpression { @@ -233,13 +247,7 @@ impl VrUser for IrExpression { match self { IrExpression::Parameter(_) => HashSet::new(), IrExpression::Variable(ir_variable) => { - if let IrVariableDescriptor::VirtualRegister(vr_variable) = - ir_variable.borrow().descriptor() - { - HashSet::from([vr_variable.clone()]) - } else { - HashSet::new() - } + ir_variable.borrow().descriptor().vr_variable_descriptors() } IrExpression::Int(_) => HashSet::new(), IrExpression::Double(_) => HashSet::new(), diff --git a/dmc-lib/src/ir/ir_parameter.rs b/dmc-lib/src/ir/ir_parameter.rs index 72934e1..72e1899 100644 --- a/dmc-lib/src/ir/ir_parameter.rs +++ b/dmc-lib/src/ir/ir_parameter.rs @@ -1,4 +1,5 @@ use crate::type_info::TypeInfo; +use dvm_lib::instruction::Location; use std::fmt::{Display, Formatter}; use std::rc::Rc; @@ -24,6 +25,10 @@ impl IrParameter { pub fn stack_offset(&self) -> isize { self.stack_offset } + + pub fn as_location(&self) -> Location { + Location::StackFrameOffset(self.stack_offset) + } } impl Display for IrParameter { diff --git a/dmc-lib/src/type_info.rs b/dmc-lib/src/type_info.rs index 80ddd34..c3ece06 100644 --- a/dmc-lib/src/type_info.rs +++ b/dmc-lib/src/type_info.rs @@ -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 { pub fn from_declared_name( 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 { match self { TypeInfo::Integer => { @@ -127,15 +190,7 @@ impl TypeInfo { } pub fn can_subtract(&self, rhs: &Self) -> bool { - match self { - TypeInfo::Integer => { - matches!(rhs, TypeInfo::Integer | TypeInfo::Double) - } - TypeInfo::Double => { - matches!(rhs, TypeInfo::Integer | TypeInfo::Double) - } - _ => false, - } + are_numbers(self, rhs) } pub fn subtract_result(&self, rhs: &Self) -> TypeInfo { @@ -153,15 +208,43 @@ impl TypeInfo { } } - pub fn can_negate(&self) -> bool { - matches!(self, TypeInfo::Integer | TypeInfo::Double) + pub fn can_left_shift(&self, rhs: &Self) -> bool { + matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer) } - pub fn negate_result(&self) -> TypeInfo { - match self { - TypeInfo::Integer => TypeInfo::Integer, - TypeInfo::Double => TypeInfo::Double, - _ => panic!(), - } + pub fn left_shift_result(&self, _rhs: &Self) -> TypeInfo { + TypeInfo::Integer + } + + 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 } } diff --git a/dvm-lib/src/instruction.rs b/dvm-lib/src/instruction.rs index f5cea84..9c02955 100644 --- a/dvm-lib/src/instruction.rs +++ b/dvm-lib/src/instruction.rs @@ -31,9 +31,12 @@ pub enum Instruction { /// (field_pointer_mut_location, operand) SetField(Location, SetFieldOperand), + Multiply(MultiplyOperand, MultiplyOperand, Location), + Divide(LocationOrNumber, LocationOrNumber, Location), + Modulo(LocationOrNumber, LocationOrNumber, Location), + Add(AddOperand, AddOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location), - Multiply(MultiplyOperand, MultiplyOperand, Location), Pop(Option), @@ -65,15 +68,24 @@ impl Display for Instruction { 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) => { write!(f, "add {}, {}, {}", left, right, destination) } Instruction::Subtract(left, right, destination) => { write!(f, "sub {}, {}, {}", left, right, destination) } - Instruction::Multiply(left, right, destination) => { - write!(f, "mul {}, {}, {}", left, right, destination) - } + Instruction::SetReturnValue(source) => { write!(f, "srv {}", source) } @@ -102,7 +114,7 @@ impl Display for Instruction { write!(f, "readf *{}, {}", field_pointer_location, destination) } Instruction::SetField(self_location, destination) => { - write!(f, "setf {}, {}", self_location, destination) + write!(f, "setf *{}, {}", self_location, destination) } } } @@ -130,6 +142,28 @@ 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 MoveOperand { Location(Location), Int(i32), diff --git a/dvm-lib/src/vm/mod.rs b/dvm-lib/src/vm/mod.rs index 0bff5ae..c282529 100644 --- a/dvm-lib/src/vm/mod.rs +++ b/dvm-lib/src/vm/mod.rs @@ -6,8 +6,9 @@ use crate::vm::function::Function; use crate::vm::object::get_object; use crate::vm::operand::Operand; use crate::vm::operand_helpers::{ - add_operand_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, + add_operand_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, }; use crate::vm::util::*; use crate::vm::value::Value; @@ -419,6 +420,72 @@ pub fn call<'a>( 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 */ Instruction::Add(left_operand, right_operand, destination) => { let left_value = add_operand_to_value( @@ -492,29 +559,6 @@ pub fn call<'a>( put_value(registers, call_stack.top_mut(), destination, result); call_stack.top_mut().increment_ip(); } - 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(); - } /* Pop instructions */ Instruction::Pop(maybe_location) => { diff --git a/dvm-lib/src/vm/operand_helpers.rs b/dvm-lib/src/vm/operand_helpers.rs index e5883b5..ef0baf9 100644 --- a/dvm-lib/src/vm/operand_helpers.rs +++ b/dvm-lib/src/vm/operand_helpers.rs @@ -1,6 +1,6 @@ use crate::instruction::{ - AddOperand, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SetFieldOperand, - SubtractOperand, + AddOperand, LocationOrNumber, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, + SetFieldOperand, SubtractOperand, }; use crate::vm::CallFrame; use crate::vm::constant::Constant; @@ -138,3 +138,20 @@ pub fn set_field_operand_to_value( 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), + } +}