A lot of work just to do subtraction.
This commit is contained in:
parent
e35bacb583
commit
ebca87ddb9
@ -155,7 +155,9 @@ impl Expression {
|
|||||||
.add_statement(IrStatement::Assign(assign));
|
.add_statement(IrStatement::Assign(assign));
|
||||||
Some(IrExpression::Variable(as_rc))
|
Some(IrExpression::Variable(as_rc))
|
||||||
}
|
}
|
||||||
Expression::Subtract(subtract_expression) => todo!(),
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
Some(subtract_expression.to_ir_expression(builder, symbol_table))
|
||||||
|
}
|
||||||
Expression::Negative(_) => todo!(),
|
Expression::Negative(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,7 +114,9 @@ impl LetStatement {
|
|||||||
Expression::Add(additive_expression) => {
|
Expression::Add(additive_expression) => {
|
||||||
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
||||||
}
|
}
|
||||||
Expression::Subtract(subtract_expression) => todo!(),
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
IrOperation::Subtract(subtract_expression.to_ir_subtract(builder, symbol_table))
|
||||||
|
}
|
||||||
Expression::Negative(_) => todo!(),
|
Expression::Negative(_) => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,17 @@
|
|||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::ir::ir_assign::IrAssign;
|
||||||
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_operation::IrOperation;
|
||||||
|
use crate::ir::ir_statement::IrStatement;
|
||||||
|
use crate::ir::ir_subtract::IrSubtract;
|
||||||
|
use crate::ir::ir_variable::IrVariable;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct SubtractExpression {
|
pub struct SubtractExpression {
|
||||||
lhs: Box<Expression>,
|
lhs: Box<Expression>,
|
||||||
@ -88,4 +97,39 @@ impl SubtractExpression {
|
|||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
&self.source_range
|
&self.source_range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_ir_subtract(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> IrSubtract {
|
||||||
|
let lhs = self
|
||||||
|
.lhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
|
.expect("Attempt to subtract non-expression");
|
||||||
|
let rhs = self
|
||||||
|
.rhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
|
.expect("Attempt to subtract non-expression");
|
||||||
|
IrSubtract::new(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ir_expression(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> IrExpression {
|
||||||
|
let ir_subtract = self.to_ir_subtract(builder, symbol_table);
|
||||||
|
let t_var = IrVariable::new_vr(
|
||||||
|
builder.new_t_var().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
self.type_info(),
|
||||||
|
);
|
||||||
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Subtract(ir_subtract));
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(assign));
|
||||||
|
IrExpression::Variable(as_rc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,6 +97,10 @@ impl Assemble for IrAssign {
|
|||||||
let (left, right) = ir_add.operand_pair(constants_table);
|
let (left, right) = ir_add.operand_pair(constants_table);
|
||||||
builder.push(Instruction::Add(left, right, destination));
|
builder.push(Instruction::Add(left, right, destination));
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
let (left, right) = ir_subtract.operand_pair();
|
||||||
|
builder.push(Instruction::Subtract(left, right, destination));
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.assemble(builder, constants_table);
|
ir_call.assemble(builder, constants_table);
|
||||||
builder.push(Instruction::Pop(Some(destination)));
|
builder.push(Instruction::Pop(Some(destination)));
|
||||||
|
|||||||
@ -5,7 +5,9 @@ use crate::ir::ir_variable::{
|
|||||||
};
|
};
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand};
|
use dvm_lib::instruction::{
|
||||||
|
AddOperand, Location, MoveOperand, PushOperand, ReturnOperand, SubtractOperand,
|
||||||
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -105,6 +107,40 @@ impl IrExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subtract_operand(&self) -> SubtractOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||||
|
TypeInfo::Integer => SubtractOperand::Location(Location::StackFrameOffset(
|
||||||
|
ir_parameter.stack_offset(),
|
||||||
|
)),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to subtract with non-integer type (found {})",
|
||||||
|
ir_parameter.type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
||||||
|
TypeInfo::Integer => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||||
|
SubtractOperand::Location(Location::Register(
|
||||||
|
vr_variable.assigned_register(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => SubtractOperand::Location(
|
||||||
|
Location::StackFrameOffset(stack_variable.offset()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to subtract with non-integer type (found {})",
|
||||||
|
ir_variable.borrow().type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => SubtractOperand::Int(*i),
|
||||||
|
IrExpression::String(_) => {
|
||||||
|
panic!("Attempt to subtract with a string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
||||||
match self {
|
match self {
|
||||||
IrExpression::Parameter(ir_parameter) => {
|
IrExpression::Parameter(ir_parameter) => {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::ir::ir_add::IrAdd;
|
use crate::ir::ir_add::IrAdd;
|
||||||
use crate::ir::ir_call::IrCall;
|
use crate::ir::ir_call::IrCall;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_subtract::IrSubtract;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -9,6 +10,7 @@ use std::fmt::{Display, Formatter};
|
|||||||
pub enum IrOperation {
|
pub enum IrOperation {
|
||||||
Load(IrExpression),
|
Load(IrExpression),
|
||||||
Add(IrAdd),
|
Add(IrAdd),
|
||||||
|
Subtract(IrSubtract),
|
||||||
Call(IrCall),
|
Call(IrCall),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ impl Display for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
write!(f, "{}", ir_add)
|
write!(f, "{}", ir_add)
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
write!(f, "{}", ir_subtract)
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
write!(f, "{}", ir_call)
|
write!(f, "{}", ir_call)
|
||||||
}
|
}
|
||||||
@ -33,6 +38,7 @@ impl VrUser for IrOperation {
|
|||||||
match self {
|
match self {
|
||||||
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
||||||
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
||||||
|
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(),
|
||||||
IrOperation::Call(ir_call) => ir_call.vr_definitions(),
|
IrOperation::Call(ir_call) => ir_call.vr_definitions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +47,7 @@ impl VrUser for IrOperation {
|
|||||||
match self {
|
match self {
|
||||||
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
||||||
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
||||||
|
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
|
||||||
IrOperation::Call(ir_call) => ir_call.vr_uses(),
|
IrOperation::Call(ir_call) => ir_call.vr_uses(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,6 +60,9 @@ impl VrUser for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
ir_add.propagate_spills(spills);
|
ir_add.propagate_spills(spills);
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
ir_subtract.propagate_spills(spills);
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.propagate_spills(spills);
|
ir_call.propagate_spills(spills);
|
||||||
}
|
}
|
||||||
@ -70,6 +80,9 @@ impl VrUser for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
ir_add.propagate_register_assignments(assignments);
|
ir_add.propagate_register_assignments(assignments);
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
ir_subtract.propagate_register_assignments(assignments);
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.propagate_register_assignments(assignments);
|
ir_call.propagate_register_assignments(assignments);
|
||||||
}
|
}
|
||||||
|
|||||||
63
dmc-lib/src/ir/ir_subtract.rs
Normal file
63
dmc-lib/src/ir/ir_subtract.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
|
use dvm_lib::instruction::SubtractOperand;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
pub struct IrSubtract {
|
||||||
|
left: Box<IrExpression>,
|
||||||
|
right: Box<IrExpression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrSubtract {
|
||||||
|
pub fn new(left: IrExpression, right: IrExpression) -> Self {
|
||||||
|
Self {
|
||||||
|
left: left.into(),
|
||||||
|
right: right.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand_pair(&self) -> (SubtractOperand, SubtractOperand) {
|
||||||
|
(self.left.subtract_operand(), self.right.subtract_operand())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VrUser for IrSubtract {
|
||||||
|
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||||
|
[&self.left, &self.right]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|expression| expression.vr_definitions())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||||
|
[&self.left, &self.right]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|expression| expression.vr_uses())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||||
|
self.left.propagate_spills(spills);
|
||||||
|
self.right.propagate_spills(spills);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_register_assignments(
|
||||||
|
&mut self,
|
||||||
|
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||||
|
) {
|
||||||
|
self.left.propagate_register_assignments(assignments);
|
||||||
|
self.right.propagate_register_assignments(assignments);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for IrSubtract {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{} - {}", self.left, self.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,5 +9,6 @@ pub mod ir_operation;
|
|||||||
pub mod ir_parameter;
|
pub mod ir_parameter;
|
||||||
pub mod ir_return;
|
pub mod ir_return;
|
||||||
pub mod ir_statement;
|
pub mod ir_statement;
|
||||||
|
pub mod ir_subtract;
|
||||||
pub mod ir_variable;
|
pub mod ir_variable;
|
||||||
mod register_allocation;
|
mod register_allocation;
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub enum Instruction {
|
|||||||
InvokePlatformStatic(FunctionName, ArgCount),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
Add(AddOperand, AddOperand, Location),
|
Add(AddOperand, AddOperand, Location),
|
||||||
|
Subtract(SubtractOperand, SubtractOperand, Location),
|
||||||
|
|
||||||
Pop(Option<Location>),
|
Pop(Option<Location>),
|
||||||
|
|
||||||
@ -50,6 +51,9 @@ impl Display for Instruction {
|
|||||||
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) => {
|
||||||
|
write!(f, "sub {}, {}, {}", left, right, destination)
|
||||||
|
}
|
||||||
Instruction::SetReturnValue(source) => {
|
Instruction::SetReturnValue(source) => {
|
||||||
write!(f, "srv {}", source)
|
write!(f, "srv {}", source)
|
||||||
}
|
}
|
||||||
@ -148,6 +152,24 @@ impl Display for AddOperand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SubtractOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ReturnOperand {
|
pub enum ReturnOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
|||||||
21
dvm-lib/src/vm/instruction_helpers.rs
Normal file
21
dvm-lib/src/vm/instruction_helpers.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::instruction::SubtractOperand;
|
||||||
|
use crate::vm::CallFrame;
|
||||||
|
use crate::vm::value::Value;
|
||||||
|
use crate::vm::value_util::load_value;
|
||||||
|
|
||||||
|
pub fn subtract_operand_to_value(
|
||||||
|
subtract_operand: &SubtractOperand,
|
||||||
|
registers: &[Value],
|
||||||
|
current_frame: &CallFrame,
|
||||||
|
) -> Value {
|
||||||
|
match subtract_operand {
|
||||||
|
SubtractOperand::Location(location) => load_value(
|
||||||
|
registers,
|
||||||
|
current_frame.stack(),
|
||||||
|
current_frame.fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
SubtractOperand::Int(i) => Value::Int(*i),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,19 @@
|
|||||||
use crate::instruction::{
|
use crate::instruction::{AddOperand, Instruction, MoveOperand, PushOperand, ReturnOperand};
|
||||||
AddOperand, ConstantName, Instruction, Location, MoveOperand, PushOperand, ReturnOperand,
|
|
||||||
};
|
|
||||||
use crate::platform_function::PlatformFunction;
|
use crate::platform_function::PlatformFunction;
|
||||||
use crate::vm::constant::Constant;
|
use crate::vm::constant::Constant;
|
||||||
use crate::vm::function::Function;
|
use crate::vm::function::Function;
|
||||||
|
use crate::vm::instruction_helpers::subtract_operand_to_value;
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
|
use crate::vm::value_util::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
|
mod instruction_helpers;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
mod value_util;
|
||||||
|
|
||||||
pub struct DvmContext {
|
pub struct DvmContext {
|
||||||
functions: HashMap<Rc<str>, Function>,
|
functions: HashMap<Rc<str>, Function>,
|
||||||
@ -165,55 +167,6 @@ impl<'a> CallStack<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_value<'a>(
|
|
||||||
registers: &'a [Value],
|
|
||||||
stack: &'a [Value],
|
|
||||||
fp: usize,
|
|
||||||
location: &Location,
|
|
||||||
) -> &'a Value {
|
|
||||||
match location {
|
|
||||||
Location::Register(register) => ®isters[*register],
|
|
||||||
Location::StackFrameOffset(offset) => {
|
|
||||||
let value_index = fp.checked_add_signed(*offset).expect(&format!(
|
|
||||||
"Overflow when adding offset {} to fp {}",
|
|
||||||
*offset, fp
|
|
||||||
));
|
|
||||||
&stack[value_index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_constant_value(
|
|
||||||
constants: &HashMap<Rc<str>, Constant>,
|
|
||||||
constant_name: &ConstantName,
|
|
||||||
) -> Value {
|
|
||||||
let constant = &constants[constant_name];
|
|
||||||
match constant {
|
|
||||||
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_value(
|
|
||||||
registers: &mut Vec<Value>,
|
|
||||||
stack: &mut Vec<Value>,
|
|
||||||
fp: usize,
|
|
||||||
destination: &Location,
|
|
||||||
value: Value,
|
|
||||||
) {
|
|
||||||
match destination {
|
|
||||||
Location::Register(register) => {
|
|
||||||
registers[*register] = value;
|
|
||||||
}
|
|
||||||
Location::StackFrameOffset(offset) => {
|
|
||||||
let target_index = fp.checked_add_signed(*offset).expect(&format!(
|
|
||||||
"Failed to calculate target index from fp + offset ({} + {})",
|
|
||||||
fp, offset
|
|
||||||
));
|
|
||||||
stack[target_index] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call<'a>(
|
pub fn call<'a>(
|
||||||
context: &'a DvmContext,
|
context: &'a DvmContext,
|
||||||
registers: &mut Vec<Value>,
|
registers: &mut Vec<Value>,
|
||||||
@ -277,14 +230,7 @@ pub fn call<'a>(
|
|||||||
load_constant_value(context.constants(), constant_name)
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let fp = call_stack.top().fp();
|
put_value(registers, call_stack.top_mut(), destination, value);
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut().stack_mut(),
|
|
||||||
fp,
|
|
||||||
destination,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,21 +347,17 @@ pub fn call<'a>(
|
|||||||
if let Value::Int(left) = left_value {
|
if let Value::Int(left) = left_value {
|
||||||
if let Value::Int(right) = right_value {
|
if let Value::Int(right) = right_value {
|
||||||
let result = left + right;
|
let result = left + right;
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::Int(result),
|
Value::Int(result),
|
||||||
);
|
);
|
||||||
} else if let Value::String(s) = right_value {
|
} else if let Value::String(s) = right_value {
|
||||||
let result = format!("{}{}", left, s);
|
let result = format!("{}{}", left, s);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
@ -425,21 +367,17 @@ pub fn call<'a>(
|
|||||||
} else if let Value::String(left) = left_value {
|
} else if let Value::String(left) = left_value {
|
||||||
if let Value::Int(right) = right_value {
|
if let Value::Int(right) = right_value {
|
||||||
let result = format!("{}{}", left, right);
|
let result = format!("{}{}", left, right);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
} else if let Value::String(right) = right_value {
|
} else if let Value::String(right) = right_value {
|
||||||
let result = format!("{}{}", left, right);
|
let result = format!("{}{}", left, right);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
@ -452,19 +390,21 @@ pub fn call<'a>(
|
|||||||
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
Instruction::Subtract(left_operand, right_operand, destination) => {
|
||||||
|
let left = subtract_operand_to_value(left_operand, registers, call_stack.top())
|
||||||
|
.unwrap_int();
|
||||||
|
let right = subtract_operand_to_value(right_operand, registers, call_stack.top())
|
||||||
|
.unwrap_int();
|
||||||
|
let result = Value::Int(left - right);
|
||||||
|
put_value(registers, call_stack.top_mut(), destination, result);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
|
}
|
||||||
|
|
||||||
/* Pop instructions */
|
/* Pop instructions */
|
||||||
Instruction::Pop(maybe_location) => {
|
Instruction::Pop(maybe_location) => {
|
||||||
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
||||||
if let Some(location) = maybe_location {
|
if let Some(location) = maybe_location {
|
||||||
let fp = call_stack.top().fp();
|
put_value(registers, call_stack.top_mut(), location, value);
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut().stack_mut(),
|
|
||||||
fp,
|
|
||||||
location,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|||||||
55
dvm-lib/src/vm/value_util.rs
Normal file
55
dvm-lib/src/vm/value_util.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::instruction::{ConstantName, Location};
|
||||||
|
use crate::vm::CallFrame;
|
||||||
|
use crate::vm::constant::Constant;
|
||||||
|
use crate::vm::value::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn load_value<'a>(
|
||||||
|
registers: &'a [Value],
|
||||||
|
stack: &'a [Value],
|
||||||
|
fp: usize,
|
||||||
|
location: &Location,
|
||||||
|
) -> &'a Value {
|
||||||
|
match location {
|
||||||
|
Location::Register(register) => ®isters[*register],
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let value_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Overflow when adding offset {} to fp {}",
|
||||||
|
*offset, fp
|
||||||
|
));
|
||||||
|
&stack[value_index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_constant_value(
|
||||||
|
constants: &HashMap<Rc<str>, Constant>,
|
||||||
|
constant_name: &ConstantName,
|
||||||
|
) -> Value {
|
||||||
|
let constant = &constants[constant_name];
|
||||||
|
match constant {
|
||||||
|
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_value(
|
||||||
|
registers: &mut Vec<Value>,
|
||||||
|
current_frame: &mut CallFrame,
|
||||||
|
destination: &Location,
|
||||||
|
value: Value,
|
||||||
|
) {
|
||||||
|
match destination {
|
||||||
|
Location::Register(register) => {
|
||||||
|
registers[*register] = value;
|
||||||
|
}
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let fp = current_frame.fp();
|
||||||
|
let target_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Failed to calculate target index from fp + offset ({} + {})",
|
||||||
|
fp, offset
|
||||||
|
));
|
||||||
|
current_frame.stack_mut()[target_index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -131,4 +131,9 @@ mod e2e_tests {
|
|||||||
Value::String(Rc::from("Hello. 1 plus 2 is 3")),
|
Value::String(Rc::from("Hello. 1 plus 2 is 3")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_subtract() {
|
||||||
|
assert_result("fn sub() -> Int 3 - 2 end", "sub", &vec![], Value::Int(1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
examples/subtract.dm
Normal file
16
examples/subtract.dm
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn add(a: Int, b: Int) -> Int
|
||||||
|
a + b
|
||||||
|
end
|
||||||
|
|
||||||
|
fn subtract(a: Int, b: Int) -> Int
|
||||||
|
a - b
|
||||||
|
end
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
let a = 42
|
||||||
|
let b = 42
|
||||||
|
println(add(a, b))
|
||||||
|
println(subtract(a, b))
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user