use std::fmt::{Display, Formatter}; use std::rc::Rc; pub type Register = usize; pub type StackFrameOffset = isize; pub type ConstantName = Rc; pub type FunctionName = Rc; pub type ArgCount = usize; pub type CallerPopCount = usize; pub type ClassFqn = Rc; pub type FieldIndex = usize; pub enum Instruction { Move(MoveOperand, Location), Push(PushOperand), InvokeStatic(FunctionName, ArgCount), InvokePlatformStatic(FunctionName, ArgCount), Allocate(ClassFqn, Location), /// (self_location, field_index, destination) GetFieldPointer(Location, FieldIndex, Location), /// (self_location, field_index, destination) GetFieldPointerMut(Location, FieldIndex, Location), /// (field_pointer_location, destination) ReadField(Location, Location), /// (field_pointer_mut_location, operand) SetField(Location, SetFieldOperand), Add(AddOperand, AddOperand, Location), Subtract(SubtractOperand, SubtractOperand, Location), Multiply(MultiplyOperand, MultiplyOperand, Location), Pop(Option), SetReturnValue(ReturnOperand), Return, } impl Display for Instruction { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Instruction::Move(source, destination) => { write!(f, "mov {}, {}", source, destination) } Instruction::Push(source) => write!(f, "push {}", source), Instruction::InvokeStatic(name, arg_count) => { write!(f, "invoke_static {} (arg_count: {})", name, arg_count) } Instruction::InvokePlatformStatic(name, arg_count) => { write!( f, "invoke_platform_static {} (arg_count: {})", name, arg_count ) } Instruction::Pop(maybe_destination) => { if let Some(destination) = maybe_destination { write!(f, "pop {}", destination) } else { write!(f, "pop") } } 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) } Instruction::Return => { write!(f, "ret") } Instruction::Allocate(class_fqn, location) => { write!(f, "alloc {}, {}", class_fqn, location) } Instruction::GetFieldPointer(self_location, field_index, destination) => { write!( f, "getf &{}.{}, {}", self_location, field_index, destination ) } Instruction::GetFieldPointerMut(self_location, field_index, destination) => { write!( f, "getf &mut {}.{}, {}", self_location, field_index, destination ) } Instruction::ReadField(field_pointer_location, destination) => { write!(f, "readf *{}, {}", field_pointer_location, destination) } Instruction::SetField(self_location, destination) => { write!(f, "setf {}, {}", self_location, destination) } } } } pub enum Location { Register(Register), StackFrameOffset(StackFrameOffset), } impl Display for Location { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Location::Register(register) => { write!(f, "r{}", register) } Location::StackFrameOffset(offset) => { if offset.is_positive() || *offset == 0 { write!(f, "fp+{}", offset) } else { write!(f, "fp{}", offset) } } } } } pub enum MoveOperand { Location(Location), Int(i32), Double(f64), String(Rc), } impl Display for MoveOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { MoveOperand::Location(location) => { write!(f, "{}", location) } MoveOperand::Int(i) => { write!(f, "{}", i) } MoveOperand::Double(d) => { write!(f, "{}", d) } MoveOperand::String(s) => { write!(f, "{}", s) } } } } pub enum PushOperand { Location(Location), Int(i32), Double(f64), String(Rc), } impl Display for PushOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { PushOperand::Location(location) => { write!(f, "{}", location) } PushOperand::Int(i) => { write!(f, "{}", i) } PushOperand::Double(d) => { write!(f, "{}", d) } PushOperand::String(s) => { write!(f, "{}", s) } } } } pub enum AddOperand { Location(Location), Int(i32), Double(f64), String(Rc), } impl Display for AddOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { AddOperand::Location(location) => { write!(f, "{}", location) } AddOperand::Int(i) => { write!(f, "{}", i) } AddOperand::Double(d) => { write!(f, "{}", d) } AddOperand::String(s) => { write!(f, "{}", s) } } } } pub enum SubtractOperand { Location(Location), Int(i32), Double(f64), } impl Display for SubtractOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { SubtractOperand::Location(location) => { write!(f, "{}", location) } SubtractOperand::Int(i) => { write!(f, "{}", i) } SubtractOperand::Double(d) => { write!(f, "{}", d) } } } } pub enum MultiplyOperand { Location(Location), Int(i32), Double(f64), } impl Display for MultiplyOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { MultiplyOperand::Location(location) => { write!(f, "{}", location) } MultiplyOperand::Int(i) => { write!(f, "{}", i) } MultiplyOperand::Double(d) => { write!(f, "{}", d) } } } } pub enum ReturnOperand { Location(Location), Int(i32), Double(f64), String(Rc), } impl Display for ReturnOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ReturnOperand::Location(location) => { write!(f, "{}", location) } ReturnOperand::Int(i) => { write!(f, "{}", i) } ReturnOperand::Double(d) => { write!(f, "{}", d) } ReturnOperand::String(s) => { write!(f, "{}", s) } } } } pub enum SetFieldOperand { Location(Location), Int(i32), Double(f64), String(Rc), } impl Display for SetFieldOperand { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { SetFieldOperand::Location(location) => { write!(f, "{}", location) } SetFieldOperand::Int(i) => { write!(f, "{}", i) } SetFieldOperand::Double(d) => { write!(f, "{}", d) } SetFieldOperand::String(s) => { write!(f, "{}", s) } } } }