Compare commits
4 Commits
320cdcf805
...
5be778ba80
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5be778ba80 | ||
|
|
8759c3be27 | ||
|
|
54e2a170a2 | ||
|
|
55a84a98b3 |
@ -10,7 +10,7 @@ use dmc_lib::symbol_table::SymbolTable;
|
||||
use dmc_lib::token::TokenKind;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::operand::Operand;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
@ -76,7 +76,7 @@ pub fn repl(register_count: usize) {
|
||||
);
|
||||
}
|
||||
|
||||
let mut registers = vec![Value::Null; register_count];
|
||||
let mut registers = vec![Operand::Null; register_count];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]);
|
||||
|
||||
@ -9,7 +9,7 @@ use dmc_lib::parser::parse_compilation_unit;
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::operand::Operand;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -92,7 +92,7 @@ pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usiz
|
||||
);
|
||||
}
|
||||
|
||||
let mut registers: Vec<Value> = vec![Value::Null; register_count];
|
||||
let mut registers: Vec<Operand> = vec![Operand::Null; register_count];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
let result = call(
|
||||
|
||||
@ -7,11 +7,8 @@ use crate::source_range::SourceRange;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::callable_symbol::CallableSymbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Call {
|
||||
callee: Box<Expression>,
|
||||
@ -156,12 +153,17 @@ impl Call {
|
||||
self.return_type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn get_callee_symbol(&self) -> Rc<RefCell<FunctionSymbol>> {
|
||||
fn get_callee_symbol(&self) -> CallableSymbol {
|
||||
match self.callee() {
|
||||
Expression::Identifier(identifier) => {
|
||||
let expressible_symbol = identifier.expressible_symbol();
|
||||
match expressible_symbol {
|
||||
ExpressibleSymbol::Function(function_symbol) => function_symbol.clone(),
|
||||
ExpressibleSymbol::Function(function_symbol) => {
|
||||
CallableSymbol::Function(function_symbol.clone())
|
||||
}
|
||||
ExpressibleSymbol::Class(class_symbol) => {
|
||||
CallableSymbol::Class(class_symbol.clone())
|
||||
}
|
||||
_ => panic!("Calling things other than functions not yet supported."),
|
||||
}
|
||||
}
|
||||
@ -181,12 +183,26 @@ impl Call {
|
||||
})
|
||||
.map(Option::unwrap)
|
||||
.collect();
|
||||
let function_symbol = self.get_callee_symbol();
|
||||
IrCall::new(
|
||||
function_symbol.borrow().declared_name_owned(),
|
||||
arguments,
|
||||
function_symbol.clone(),
|
||||
)
|
||||
let callable_symbol = self.get_callee_symbol();
|
||||
match callable_symbol {
|
||||
CallableSymbol::Function(function_symbol) => IrCall::new(
|
||||
function_symbol.borrow().declared_name_owned(),
|
||||
arguments,
|
||||
function_symbol.borrow().is_extern(),
|
||||
),
|
||||
CallableSymbol::Class(class_symbol) => {
|
||||
let constructor_symbol = class_symbol
|
||||
.borrow()
|
||||
.constructor_symbol()
|
||||
.cloned()
|
||||
.expect("Default constructors not supported yet.");
|
||||
IrCall::new(
|
||||
constructor_symbol.borrow().declared_name_owned(),
|
||||
arguments,
|
||||
false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
|
||||
@ -103,10 +103,13 @@ impl Class {
|
||||
}
|
||||
|
||||
// 5. gather functions
|
||||
// note: for each function, insert at index 0 a self parameter
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.gather_declared_names(symbol_table))
|
||||
.map(|function| {
|
||||
function.gather_declared_names(symbol_table, self.class_symbol.as_ref())
|
||||
})
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
@ -124,13 +127,15 @@ impl Class {
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.constructor
|
||||
.as_mut()
|
||||
.map(|constructor| constructor.check_name_usages(symbol_table))
|
||||
.map(|constructor| {
|
||||
constructor.check_name_usages(symbol_table, self.class_symbol.as_ref())
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.check_name_usages(symbol_table))
|
||||
.map(|field| field.check_name_usages(symbol_table, self.class_symbol.as_ref()))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
@ -139,13 +144,13 @@ impl Class {
|
||||
}
|
||||
|
||||
if let Some(constructor) = &mut self.constructor {
|
||||
constructor.check_name_usages(symbol_table)?;
|
||||
constructor.check_name_usages(symbol_table, self.class_symbol.as_ref())?;
|
||||
}
|
||||
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.check_name_usages(symbol_table))
|
||||
.map(|function| function.check_name_usages(symbol_table, self.class_symbol.as_ref()))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
@ -253,7 +258,10 @@ impl Class {
|
||||
}
|
||||
|
||||
for function in &self.functions {
|
||||
ir_functions.push(function.to_ir(symbol_table));
|
||||
ir_functions.push(function.to_ir(
|
||||
symbol_table,
|
||||
Some(self.class_symbol.as_ref().unwrap().clone()),
|
||||
));
|
||||
}
|
||||
|
||||
ir_functions
|
||||
@ -319,6 +327,9 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||
for ir_function in &mut ir_functions {
|
||||
println!("{}", ir_function);
|
||||
}
|
||||
let mut constants_table = ConstantsTable::new();
|
||||
for ir_function in &mut ir_functions {
|
||||
let (_, stack_size) = ir_function.assign_registers(8);
|
||||
|
||||
@ -45,7 +45,7 @@ impl CompilationUnit {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
self.functions
|
||||
.iter_mut()
|
||||
.map(|f| f.gather_declared_names(symbol_table))
|
||||
.map(|f| f.gather_declared_names(symbol_table, None))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
||||
@ -78,14 +78,14 @@ impl CompilationUnit {
|
||||
|
||||
self.functions
|
||||
.iter_mut()
|
||||
.map(|f| f.check_name_usages(symbol_table))
|
||||
.map(|f| f.check_name_usages(symbol_table, None))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
||||
|
||||
self.extern_functions
|
||||
.iter_mut()
|
||||
.map(|f| f.check_name_usages(symbol_table))
|
||||
.map(|f| f.check_name_usages(symbol_table, None))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
||||
@ -139,7 +139,7 @@ impl CompilationUnit {
|
||||
let mut functions: Vec<IrFunction> = vec![];
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|f| f.to_ir(symbol_table))
|
||||
.map(|f| f.to_ir(symbol_table, None))
|
||||
.for_each(|f| functions.push(f));
|
||||
self.classes
|
||||
.iter()
|
||||
|
||||
@ -7,8 +7,11 @@ use crate::ir::ir_allocate::IrAllocate;
|
||||
use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_function::IrFunction;
|
||||
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
|
||||
use crate::ir::ir_operation::IrOperation;
|
||||
use crate::ir::ir_parameter::IrParameter;
|
||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||
use crate::ir::ir_return::IrReturn;
|
||||
use crate::ir::ir_set_field::IrSetField;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
@ -116,11 +119,15 @@ impl Constructor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let parameters_diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|param| param.check_name_usages(symbol_table))
|
||||
.map(|param| param.check_name_usages(symbol_table, class_context))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
@ -216,10 +223,40 @@ impl Constructor {
|
||||
// next, initialize fields that have an initializer in their declaration
|
||||
for field in fields {
|
||||
if let Some(initializer) = field.initializer() {
|
||||
// get a mut ref to the field
|
||||
let ir_get_field_ref_mut = IrGetFieldRefMut::new(
|
||||
IrParameterOrVariable::Variable(self_variable.clone()),
|
||||
field.field_symbol().borrow().field_index(),
|
||||
);
|
||||
let field_mut_ref_variable_name: Rc<str> = ir_builder.new_t_var().into();
|
||||
let field_mut_ref_variable = Rc::new(RefCell::new(IrVariable::new_vr(
|
||||
field_mut_ref_variable_name.clone(),
|
||||
ir_builder.current_block().id(),
|
||||
field.field_symbol().borrow().type_info(),
|
||||
)));
|
||||
let field_mut_ref_assign = IrAssign::new(
|
||||
field_mut_ref_variable.clone(),
|
||||
IrOperation::GetFieldRefMut(ir_get_field_ref_mut),
|
||||
);
|
||||
ir_builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Assign(field_mut_ref_assign));
|
||||
|
||||
// save the mut ref to the builder for other uses if needed
|
||||
ir_builder
|
||||
.field_mut_pointer_variables_mut()
|
||||
.insert(field_mut_ref_variable_name.clone(), field_mut_ref_variable);
|
||||
|
||||
// now write the initializer result to the field
|
||||
let field_mut_ref_variable = ir_builder
|
||||
.field_mut_pointer_variables()
|
||||
.get(&field_mut_ref_variable_name)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let ir_expression = initializer.to_ir(&mut ir_builder, symbol_table).unwrap();
|
||||
let ir_set_field = IrSetField::new(
|
||||
&self_variable.clone(),
|
||||
field.field_symbol().borrow().field_index(),
|
||||
&field_mut_ref_variable, // dumb that we clone it and then ref it
|
||||
ir_expression,
|
||||
);
|
||||
ir_builder
|
||||
@ -228,6 +265,14 @@ impl Constructor {
|
||||
}
|
||||
}
|
||||
|
||||
// return complete self object
|
||||
let ir_return_statement = IrStatement::Return(IrReturn::new(Some(IrExpression::Variable(
|
||||
self_variable.clone(),
|
||||
))));
|
||||
ir_builder
|
||||
.current_block_mut()
|
||||
.add_statement(ir_return_statement);
|
||||
|
||||
ir_builder.finish_block();
|
||||
let entry_block = ir_builder.get_block(entry_block_id);
|
||||
|
||||
|
||||
@ -149,7 +149,7 @@ impl Expression {
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
let expressible_symbol = identifier.expressible_symbol();
|
||||
Some(expressible_symbol.ir_expression())
|
||||
Some(expressible_symbol.ir_expression(builder))
|
||||
}
|
||||
Expression::Add(additive_expression) => {
|
||||
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::ast::parameter::Parameter;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
@ -104,16 +105,23 @@ impl ExternFunction {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table, class_context))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
match self.return_type.check_name_usages(symbol_table) {
|
||||
match self
|
||||
.return_type
|
||||
.check_name_usages(symbol_table, class_context)
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(mut return_type_diagnostics) => {
|
||||
diagnostics.append(&mut return_type_diagnostics);
|
||||
@ -126,7 +134,7 @@ impl ExternFunction {
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(self.return_type.to_type_info());
|
||||
.set_return_type_info(self.return_type.type_info().clone());
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::ast::expression::Expression;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
@ -95,9 +96,13 @@ impl Field {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
if let Some(type_use) = &mut self.declared_type {
|
||||
type_use.check_name_usages(symbol_table)?;
|
||||
type_use.check_name_usages(symbol_table, class_context)?;
|
||||
}
|
||||
|
||||
// This is going to get hairy, because users might attempt to use a field in an initializer
|
||||
@ -137,7 +142,7 @@ impl Field {
|
||||
match self.initializer.as_ref() {
|
||||
Some(initializer) => {
|
||||
let initializer_type_info = initializer.type_info();
|
||||
let declared_type_info = type_use.to_type_info();
|
||||
let declared_type_info = type_use.type_info();
|
||||
if declared_type_info.is_assignable_from(initializer_type_info) {
|
||||
declared_type_info
|
||||
} else {
|
||||
@ -156,14 +161,14 @@ impl Field {
|
||||
}
|
||||
None => {
|
||||
// easy: the declared type
|
||||
type_use.to_type_info()
|
||||
type_use.type_info()
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// type is the initializer
|
||||
match self.initializer.as_ref() {
|
||||
Some(initializer) => initializer.type_info().clone(),
|
||||
Some(initializer) => initializer.type_info(),
|
||||
None => {
|
||||
// this is an error
|
||||
return Err(vec![Diagnostic::new(
|
||||
@ -181,7 +186,7 @@ impl Field {
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_type_info(field_type_info);
|
||||
.set_type_info(field_type_info.clone());
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
|
||||
@ -5,9 +5,11 @@ use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_function::IrFunction;
|
||||
use crate::ir::ir_parameter::IrParameter;
|
||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::cell::RefCell;
|
||||
@ -55,6 +57,7 @@ impl Function {
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
@ -94,6 +97,20 @@ impl Function {
|
||||
|
||||
// handle parameters
|
||||
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
|
||||
|
||||
// first, if we are in a class context, insert a "fake" self parameter
|
||||
if let Some(class_symbol) = class_context {
|
||||
self.parameters.insert(
|
||||
0,
|
||||
Parameter::new(
|
||||
"self",
|
||||
SourceRange::new(0, 0),
|
||||
TypeUse::new("Self", SourceRange::new(0, 0)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// now gather all names for the params
|
||||
let mut parameter_symbols = vec![];
|
||||
for parameter in &mut self.parameters {
|
||||
match parameter.gather_declared_names(symbol_table) {
|
||||
@ -105,6 +122,8 @@ impl Function {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set params on function symbol
|
||||
function_symbol
|
||||
.borrow_mut()
|
||||
.set_parameters(parameter_symbols);
|
||||
@ -138,7 +157,11 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
// parameters
|
||||
@ -146,7 +169,7 @@ impl Function {
|
||||
&mut self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table, class_context))
|
||||
.filter_map(|result| result.err())
|
||||
.flatten()
|
||||
.collect(),
|
||||
@ -154,14 +177,14 @@ impl Function {
|
||||
|
||||
// return type
|
||||
if let Some(type_use) = &mut self.return_type {
|
||||
match type_use.check_name_usages(symbol_table) {
|
||||
match type_use.check_name_usages(symbol_table, class_context) {
|
||||
Ok(_) => {
|
||||
// set return type info on function symbol
|
||||
self.function_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(type_use.to_type_info());
|
||||
.set_return_type_info(type_use.type_info().clone());
|
||||
}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
@ -237,7 +260,11 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> IrFunction {
|
||||
pub fn to_ir(
|
||||
&self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<Rc<RefCell<ClassSymbol>>>,
|
||||
) -> IrFunction {
|
||||
let mut builder = IrBuilder::new();
|
||||
|
||||
// parameters
|
||||
@ -256,6 +283,14 @@ impl Function {
|
||||
|
||||
let entry_block_id = builder.new_block();
|
||||
|
||||
// preamble
|
||||
// if we are a method, we need to set the self parameter on the builder
|
||||
if let Some(_) = class_context {
|
||||
let parameter_0 = builder.parameters()[0].clone();
|
||||
// put it in the self parameter
|
||||
builder.set_self_parameter_or_variable(IrParameterOrVariable::IrParameter(parameter_0));
|
||||
}
|
||||
|
||||
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
||||
let return_type_info = function_symbol.return_type_info();
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use crate::ir::ir_block::IrBlock;
|
||||
use crate::ir::ir_parameter::IrParameter;
|
||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
@ -11,6 +13,9 @@ pub struct IrBuilder {
|
||||
t_var_counter: usize,
|
||||
blocks: HashMap<usize, Rc<RefCell<IrBlock>>>,
|
||||
current_block_builder: Option<IrBlockBuilder>,
|
||||
self_parameter_or_variable: Option<IrParameterOrVariable>,
|
||||
field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
|
||||
mut_field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
|
||||
}
|
||||
|
||||
impl IrBuilder {
|
||||
@ -21,6 +26,9 @@ impl IrBuilder {
|
||||
t_var_counter: 0,
|
||||
blocks: HashMap::new(),
|
||||
current_block_builder: None,
|
||||
self_parameter_or_variable: None,
|
||||
field_variables: HashMap::new(),
|
||||
mut_field_variables: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +80,37 @@ impl IrBuilder {
|
||||
self.t_var_counter += 1;
|
||||
format!("t{}", id)
|
||||
}
|
||||
|
||||
pub fn set_self_parameter_or_variable(
|
||||
&mut self,
|
||||
self_parameter_or_variable: IrParameterOrVariable,
|
||||
) {
|
||||
self.self_parameter_or_variable = Some(self_parameter_or_variable);
|
||||
}
|
||||
|
||||
pub fn self_parameter_or_variable(&self) -> &IrParameterOrVariable {
|
||||
self.self_parameter_or_variable.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn field_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
|
||||
&self.field_variables
|
||||
}
|
||||
|
||||
pub fn field_pointer_variables_mut(
|
||||
&mut self,
|
||||
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
|
||||
&mut self.field_variables
|
||||
}
|
||||
|
||||
pub fn field_mut_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
|
||||
&self.mut_field_variables
|
||||
}
|
||||
|
||||
pub fn field_mut_pointer_variables_mut(
|
||||
&mut self,
|
||||
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
|
||||
&mut self.mut_field_variables
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IrBlockBuilder {
|
||||
|
||||
@ -114,7 +114,7 @@ impl LetStatement {
|
||||
IrOperation::Load(IrExpression::String(string_literal.content().into()))
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
IrOperation::Load(identifier.expressible_symbol().ir_expression())
|
||||
IrOperation::Load(identifier.expressible_symbol().ir_expression(builder))
|
||||
}
|
||||
Expression::Add(additive_expression) => {
|
||||
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
||||
|
||||
@ -74,9 +74,6 @@ impl NegativeExpression {
|
||||
.expect("Attempt to negate non-value expression");
|
||||
|
||||
match operand_as_ir {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(parameter) => {
|
||||
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -36,7 +36,6 @@ impl Parameter {
|
||||
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
TypeInfo::from_declared_name(self.type_use.declared_name()), // todo: this will blow up if type is a Class
|
||||
));
|
||||
match insert_result {
|
||||
Ok(parameter_symbol) => {
|
||||
@ -64,8 +63,21 @@ impl Parameter {
|
||||
Ok(self.parameter_symbol.clone().unwrap())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.type_use.check_name_usages(symbol_table)?;
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// check the type use
|
||||
self.type_use
|
||||
.check_name_usages(symbol_table, class_context)?;
|
||||
|
||||
// set type on parameter symbol
|
||||
self.parameter_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_type_info(self.type_use.type_info().clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::type_symbol::{PrimitiveTypeSymbol, TypeSymbol};
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct TypeUse {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
scope_id: Option<usize>,
|
||||
type_symbol: Option<TypeSymbol>,
|
||||
type_info: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl TypeUse {
|
||||
@ -17,7 +19,7 @@ impl TypeUse {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
scope_id: None,
|
||||
type_symbol: None,
|
||||
type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,16 +35,18 @@ impl TypeUse {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let maybe_type_symbol =
|
||||
symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name);
|
||||
if let Some(type_symbol) = maybe_type_symbol {
|
||||
self.type_symbol = Some(type_symbol);
|
||||
Ok(())
|
||||
} else if let Some(primitive_type_symbol) =
|
||||
PrimitiveTypeSymbol::try_from_declared_name(self.declared_name())
|
||||
{
|
||||
self.type_symbol = Some(TypeSymbol::Primitive(primitive_type_symbol));
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
if let Some(type_info) = TypeInfo::from_declared_name(
|
||||
&self.declared_name,
|
||||
self.scope_id.unwrap(),
|
||||
symbol_table,
|
||||
class_context,
|
||||
) {
|
||||
self.type_info = Some(type_info);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vec![
|
||||
@ -60,16 +64,7 @@ impl TypeUse {
|
||||
Ok(()) // no-op, for now
|
||||
}
|
||||
|
||||
pub fn to_type_info(&self) -> TypeInfo {
|
||||
match self.type_symbol.as_ref().unwrap() {
|
||||
TypeSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()),
|
||||
TypeSymbol::Primitive(primitive_type) => match primitive_type {
|
||||
PrimitiveTypeSymbol::Any => TypeInfo::Any,
|
||||
PrimitiveTypeSymbol::Int => TypeInfo::Integer,
|
||||
PrimitiveTypeSymbol::Double => TypeInfo::Double,
|
||||
PrimitiveTypeSymbol::String => TypeInfo::String,
|
||||
PrimitiveTypeSymbol::Void => TypeInfo::Void,
|
||||
},
|
||||
}
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||
use crate::ir::ir_operation::IrOperation;
|
||||
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use dvm_lib::instruction::{Instruction, Location};
|
||||
use dvm_lib::instruction::Instruction;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -79,16 +79,35 @@ impl VrUser for IrAssign {
|
||||
|
||||
impl Assemble for IrAssign {
|
||||
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||
let destination = match self.destination.borrow().descriptor() {
|
||||
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||
Location::Register(vr_variable.assigned_register())
|
||||
}
|
||||
IrVariableDescriptor::Stack(stack_variable) => {
|
||||
Location::StackFrameOffset(stack_variable.offset())
|
||||
}
|
||||
};
|
||||
let destination = self.destination.borrow().descriptor().as_location();
|
||||
|
||||
match self.initializer.as_ref() {
|
||||
IrOperation::GetFieldRef(ir_get_field_ref) => {
|
||||
let self_location = ir_get_field_ref.self_parameter_or_variable().as_location();
|
||||
builder.push(Instruction::GetFieldPointer(
|
||||
self_location,
|
||||
ir_get_field_ref.field_index(),
|
||||
destination,
|
||||
));
|
||||
}
|
||||
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => {
|
||||
let self_location = ir_get_field_ref_mut
|
||||
.self_parameter_or_variable()
|
||||
.as_location();
|
||||
builder.push(Instruction::GetFieldPointerMut(
|
||||
self_location,
|
||||
ir_get_field_ref_mut.field_index(),
|
||||
destination,
|
||||
));
|
||||
}
|
||||
IrOperation::ReadField(ir_read_field) => {
|
||||
let field_ref_location = ir_read_field
|
||||
.field_ref_variable()
|
||||
.borrow()
|
||||
.descriptor()
|
||||
.as_location();
|
||||
builder.push(Instruction::ReadField(field_ref_location, destination));
|
||||
}
|
||||
IrOperation::Load(ir_expression) => {
|
||||
let move_operand = ir_expression.move_operand(constants_table);
|
||||
builder.push(Instruction::Move(move_operand, destination));
|
||||
|
||||
@ -154,7 +154,7 @@ mod tests {
|
||||
.find(|f| f.declared_name() == "main")
|
||||
.unwrap();
|
||||
|
||||
let mut main_ir = main.to_ir(&symbol_table);
|
||||
let mut main_ir = main.to_ir(&symbol_table, None);
|
||||
let (register_assignments, _) = main_ir.assign_registers(2);
|
||||
assert_eq!(register_assignments.len(), 4);
|
||||
}
|
||||
|
||||
@ -3,10 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use dvm_lib::instruction::Instruction;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
@ -14,19 +11,15 @@ use std::rc::Rc;
|
||||
pub struct IrCall {
|
||||
function_name: Rc<str>,
|
||||
arguments: Vec<IrExpression>,
|
||||
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||
is_extern: bool,
|
||||
}
|
||||
|
||||
impl IrCall {
|
||||
pub fn new(
|
||||
function_name: Rc<str>,
|
||||
arguments: Vec<IrExpression>,
|
||||
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||
) -> Self {
|
||||
pub fn new(function_name: Rc<str>, arguments: Vec<IrExpression>, is_extern: bool) -> Self {
|
||||
Self {
|
||||
function_name,
|
||||
arguments,
|
||||
function_symbol,
|
||||
is_extern,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,16 +60,15 @@ impl Assemble for IrCall {
|
||||
.iter()
|
||||
.map(|ir_expression| ir_expression.push_operand(constants_table))
|
||||
.for_each(|push_operand| builder.push(Instruction::Push(push_operand)));
|
||||
let symbol = self.function_symbol.borrow();
|
||||
if symbol.is_extern() {
|
||||
if self.is_extern {
|
||||
builder.push(Instruction::InvokePlatformStatic(
|
||||
symbol.declared_name_owned(),
|
||||
symbol.parameters().len(),
|
||||
self.function_name.clone(),
|
||||
self.arguments.len(),
|
||||
));
|
||||
} else {
|
||||
builder.push(Instruction::InvokeStatic(
|
||||
symbol.declared_name_owned(),
|
||||
symbol.parameters().len(),
|
||||
self.function_name.clone(),
|
||||
self.arguments.len(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum IrExpression {
|
||||
Field(Rc<RefCell<IrVariable>>, usize),
|
||||
Parameter(Rc<IrParameter>),
|
||||
Variable(Rc<RefCell<IrVariable>>),
|
||||
Int(i32),
|
||||
@ -26,9 +25,6 @@ pub enum IrExpression {
|
||||
impl IrExpression {
|
||||
pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
@ -51,9 +47,6 @@ impl IrExpression {
|
||||
|
||||
pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
@ -76,9 +69,6 @@ impl IrExpression {
|
||||
|
||||
pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||
TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => {
|
||||
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
@ -117,9 +107,6 @@ impl IrExpression {
|
||||
|
||||
pub fn subtract_operand(&self) -> SubtractOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||
TypeInfo::Integer | TypeInfo::Double => SubtractOperand::Location(
|
||||
Location::StackFrameOffset(ir_parameter.stack_offset()),
|
||||
@ -155,9 +142,6 @@ impl IrExpression {
|
||||
|
||||
pub fn multiply_operand(&self) -> MultiplyOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
@ -179,9 +163,6 @@ impl IrExpression {
|
||||
|
||||
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
@ -206,9 +187,6 @@ impl IrExpression {
|
||||
|
||||
pub fn set_field_operand(&self, constants_table: &mut ConstantsTable) -> SetFieldOperand {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, _) => {
|
||||
todo!()
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
SetFieldOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
@ -233,9 +211,6 @@ impl IrExpression {
|
||||
impl Display for IrExpression {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, field_index) => {
|
||||
write!(f, "{}.{}", self_variable.borrow(), field_index)
|
||||
}
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
write!(f, "{}", ir_parameter)
|
||||
}
|
||||
@ -263,15 +238,6 @@ impl VrUser for IrExpression {
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, field_index) => {
|
||||
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
|
||||
self_variable.borrow().descriptor()
|
||||
{
|
||||
HashSet::from([vr_variable.clone()])
|
||||
} else {
|
||||
HashSet::new()
|
||||
}
|
||||
}
|
||||
IrExpression::Parameter(_) => HashSet::new(),
|
||||
IrExpression::Variable(ir_variable) => {
|
||||
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
|
||||
@ -290,9 +256,6 @@ impl VrUser for IrExpression {
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, field_index) => {
|
||||
// no-op, no defs
|
||||
}
|
||||
IrExpression::Parameter(_) => {
|
||||
// no-op
|
||||
}
|
||||
@ -329,9 +292,6 @@ impl VrUser for IrExpression {
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
match self {
|
||||
IrExpression::Field(self_variable, field_index) => {
|
||||
// no-op
|
||||
}
|
||||
IrExpression::Parameter(_) => {
|
||||
// no-op
|
||||
}
|
||||
|
||||
57
dmc-lib/src/ir/ir_get_field_ref.rs
Normal file
57
dmc-lib/src/ir/ir_get_field_ref.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
pub struct IrGetFieldRef {
|
||||
self_parameter_or_variable: IrParameterOrVariable,
|
||||
field_index: usize,
|
||||
}
|
||||
|
||||
impl IrGetFieldRef {
|
||||
pub fn new(self_parameter_or_variable: IrParameterOrVariable, field_index: usize) -> Self {
|
||||
Self {
|
||||
self_parameter_or_variable,
|
||||
field_index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn self_parameter_or_variable(&self) -> &IrParameterOrVariable {
|
||||
&self.self_parameter_or_variable
|
||||
}
|
||||
|
||||
pub fn field_index(&self) -> usize {
|
||||
self.field_index
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrGetFieldRef {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"&{}.{}",
|
||||
self.self_parameter_or_variable, self.field_index
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl VrUser for IrGetFieldRef {
|
||||
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
|
||||
|
||||
fn propagate_register_assignments(
|
||||
&mut self,
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
|
||||
}
|
||||
58
dmc-lib/src/ir/ir_get_field_ref_mut.rs
Normal file
58
dmc-lib/src/ir/ir_get_field_ref_mut.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
pub struct IrGetFieldRefMut {
|
||||
self_parameter_or_variable: IrParameterOrVariable,
|
||||
field_index: usize,
|
||||
}
|
||||
|
||||
impl IrGetFieldRefMut {
|
||||
pub fn new(self_parameter_or_variable: IrParameterOrVariable, field_index: usize) -> Self {
|
||||
Self {
|
||||
self_parameter_or_variable,
|
||||
field_index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn self_parameter_or_variable(&self) -> &IrParameterOrVariable {
|
||||
&self.self_parameter_or_variable
|
||||
}
|
||||
|
||||
pub fn field_index(&self) -> usize {
|
||||
self.field_index
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrGetFieldRefMut {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"&mut {}.{}",
|
||||
self.self_parameter_or_variable,
|
||||
self.field_index()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl VrUser for IrGetFieldRefMut {
|
||||
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
|
||||
|
||||
fn propagate_register_assignments(
|
||||
&mut self,
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
|
||||
}
|
||||
@ -2,7 +2,10 @@ use crate::ir::ir_add::IrAdd;
|
||||
use crate::ir::ir_allocate::IrAllocate;
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_get_field_ref::IrGetFieldRef;
|
||||
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
|
||||
use crate::ir::ir_multiply::IrMultiply;
|
||||
use crate::ir::ir_read_field::IrReadField;
|
||||
use crate::ir::ir_subtract::IrSubtract;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
@ -10,6 +13,9 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
pub enum IrOperation {
|
||||
GetFieldRef(IrGetFieldRef),
|
||||
GetFieldRefMut(IrGetFieldRefMut),
|
||||
ReadField(IrReadField),
|
||||
Load(IrExpression),
|
||||
Add(IrAdd),
|
||||
Subtract(IrSubtract),
|
||||
@ -21,6 +27,15 @@ pub enum IrOperation {
|
||||
impl Display for IrOperation {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
IrOperation::GetFieldRef(ir_get_field_ref) => {
|
||||
write!(f, "{}", ir_get_field_ref)
|
||||
}
|
||||
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => {
|
||||
write!(f, "{}", ir_get_field_ref_mut)
|
||||
}
|
||||
IrOperation::ReadField(ir_read_field) => {
|
||||
write!(f, "{}", ir_read_field)
|
||||
}
|
||||
IrOperation::Load(ir_expression) => {
|
||||
write!(f, "{}", ir_expression)
|
||||
}
|
||||
@ -46,6 +61,9 @@ impl Display for IrOperation {
|
||||
impl VrUser for IrOperation {
|
||||
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
match self {
|
||||
IrOperation::GetFieldRef(_) => HashSet::new(),
|
||||
IrOperation::GetFieldRefMut(_) => HashSet::new(),
|
||||
IrOperation::ReadField(_) => HashSet::new(),
|
||||
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
||||
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
||||
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(),
|
||||
@ -57,6 +75,9 @@ impl VrUser for IrOperation {
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
match self {
|
||||
IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(),
|
||||
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(),
|
||||
IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(),
|
||||
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
||||
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
||||
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
|
||||
@ -68,6 +89,9 @@ impl VrUser for IrOperation {
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||
match self {
|
||||
IrOperation::GetFieldRef(_) => {}
|
||||
IrOperation::GetFieldRefMut(_) => {}
|
||||
IrOperation::ReadField(_) => {}
|
||||
IrOperation::Load(ir_expression) => {
|
||||
ir_expression.propagate_spills(spills);
|
||||
}
|
||||
@ -92,6 +116,9 @@ impl VrUser for IrOperation {
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
match self {
|
||||
IrOperation::GetFieldRef(_) => {}
|
||||
IrOperation::GetFieldRefMut(_) => {}
|
||||
IrOperation::ReadField(_) => {}
|
||||
IrOperation::Load(ir_expression) => {
|
||||
ir_expression.propagate_register_assignments(assignments);
|
||||
}
|
||||
|
||||
38
dmc-lib/src/ir/ir_parameter_or_variable.rs
Normal file
38
dmc-lib/src/ir/ir_parameter_or_variable.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::ir::ir_parameter::IrParameter;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use dvm_lib::instruction::Location;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum IrParameterOrVariable {
|
||||
IrParameter(Rc<IrParameter>),
|
||||
Variable(Rc<RefCell<IrVariable>>),
|
||||
}
|
||||
|
||||
impl IrParameterOrVariable {
|
||||
pub fn as_location(&self) -> Location {
|
||||
match self {
|
||||
IrParameterOrVariable::IrParameter(ir_parameter) => {
|
||||
Location::StackFrameOffset(ir_parameter.stack_offset())
|
||||
}
|
||||
IrParameterOrVariable::Variable(ir_variable) => {
|
||||
ir_variable.borrow().descriptor().as_location()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrParameterOrVariable {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
IrParameterOrVariable::IrParameter(ir_parameter) => {
|
||||
write!(f, "{}", ir_parameter)
|
||||
}
|
||||
IrParameterOrVariable::Variable(ir_variable) => {
|
||||
write!(f, "{}", ir_variable.borrow())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
dmc-lib/src/ir/ir_read_field.rs
Normal file
52
dmc-lib/src/ir/ir_read_field.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct IrReadField {
|
||||
field_ref_variable: Rc<RefCell<IrVariable>>,
|
||||
}
|
||||
|
||||
impl IrReadField {
|
||||
pub fn new(field_ref_variable: Rc<RefCell<IrVariable>>) -> Self {
|
||||
Self { field_ref_variable }
|
||||
}
|
||||
|
||||
pub fn field_ref_variable(&self) -> &Rc<RefCell<IrVariable>> {
|
||||
&self.field_ref_variable
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrReadField {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.field_ref_variable.borrow(),)
|
||||
}
|
||||
}
|
||||
|
||||
impl VrUser for IrReadField {
|
||||
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
HashSet::new()
|
||||
}
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
let mut set = HashSet::new();
|
||||
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
|
||||
self.field_ref_variable.borrow().descriptor()
|
||||
{
|
||||
set.insert(vr_variable.clone());
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
|
||||
|
||||
fn propagate_register_assignments(
|
||||
&mut self,
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
|
||||
}
|
||||
@ -53,9 +53,8 @@ impl VrUser for IrReturn {
|
||||
impl Assemble for IrReturn {
|
||||
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||
if let Some(ir_expression) = self.value.as_ref() {
|
||||
builder.push(Instruction::SetReturnValue(
|
||||
ir_expression.return_operand(constants_table),
|
||||
));
|
||||
let return_operand = ir_expression.return_operand(constants_table);
|
||||
builder.push(Instruction::SetReturnValue(return_operand));
|
||||
}
|
||||
builder.push(Instruction::Return);
|
||||
}
|
||||
|
||||
@ -4,27 +4,21 @@ use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use crate::ir::util::propagate_spills;
|
||||
use dvm_lib::instruction::{Instruction, Location};
|
||||
use dvm_lib::instruction::Instruction;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct IrSetField {
|
||||
target_object: Rc<RefCell<IrVariable>>,
|
||||
field_index: usize,
|
||||
field_ref_variable: Rc<RefCell<IrVariable>>,
|
||||
initializer: Box<IrExpression>,
|
||||
}
|
||||
|
||||
impl IrSetField {
|
||||
pub fn new(
|
||||
target_object: &Rc<RefCell<IrVariable>>,
|
||||
field_index: usize,
|
||||
initializer: IrExpression,
|
||||
) -> Self {
|
||||
pub fn new(field_ref_variable: &Rc<RefCell<IrVariable>>, initializer: IrExpression) -> Self {
|
||||
Self {
|
||||
target_object: target_object.clone(),
|
||||
field_index,
|
||||
field_ref_variable: field_ref_variable.clone(),
|
||||
initializer: initializer.into(),
|
||||
}
|
||||
}
|
||||
@ -38,7 +32,7 @@ impl VrUser for IrSetField {
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
let mut set = HashSet::new();
|
||||
match self.target_object.borrow().descriptor() {
|
||||
match self.field_ref_variable.borrow().descriptor() {
|
||||
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||
set.insert(vr_variable.clone());
|
||||
}
|
||||
@ -49,7 +43,7 @@ impl VrUser for IrSetField {
|
||||
}
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||
propagate_spills(&mut self.target_object, spills);
|
||||
propagate_spills(&mut self.field_ref_variable, spills);
|
||||
self.initializer.propagate_spills(spills);
|
||||
}
|
||||
|
||||
@ -67,21 +61,9 @@ impl VrUser for IrSetField {
|
||||
|
||||
impl Assemble for IrSetField {
|
||||
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||
let destination = match self.target_object.borrow().descriptor() {
|
||||
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||
Location::Register(vr_variable.assigned_register())
|
||||
}
|
||||
IrVariableDescriptor::Stack(stack_variable) => {
|
||||
Location::StackFrameOffset(stack_variable.offset())
|
||||
}
|
||||
};
|
||||
|
||||
let field_ref_location = self.field_ref_variable.borrow().descriptor().as_location();
|
||||
let set_field_operand = self.initializer.set_field_operand(constants_table);
|
||||
builder.push(Instruction::SetField(
|
||||
destination,
|
||||
self.field_index,
|
||||
set_field_operand,
|
||||
));
|
||||
builder.push(Instruction::SetField(field_ref_location, set_field_operand));
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +71,8 @@ impl Display for IrSetField {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}.{} = {}",
|
||||
self.target_object.borrow(),
|
||||
self.field_index,
|
||||
"*{} = {}",
|
||||
self.field_ref_variable.borrow(),
|
||||
self.initializer
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::type_info::TypeInfo;
|
||||
use dvm_lib::instruction::Location;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
@ -80,6 +81,15 @@ impl IrVariableDescriptor {
|
||||
IrVariableDescriptor::Stack(stack_variable) => stack_variable.name_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_location(&self) -> Location {
|
||||
match self {
|
||||
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||
register_variable.as_location()
|
||||
}
|
||||
IrVariableDescriptor::Stack(stack_variable) => stack_variable.as_location(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
@ -117,6 +127,10 @@ impl IrVrVariableDescriptor {
|
||||
pub fn assigned_register(&self) -> usize {
|
||||
self.assigned_register.unwrap()
|
||||
}
|
||||
|
||||
pub fn as_location(&self) -> Location {
|
||||
Location::Register(self.assigned_register.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrVrVariableDescriptor {
|
||||
@ -161,6 +175,10 @@ impl IrStackVariableDescriptor {
|
||||
pub fn offset(&self) -> isize {
|
||||
self.offset.unwrap()
|
||||
}
|
||||
|
||||
pub fn as_location(&self) -> Location {
|
||||
Location::StackFrameOffset(self.offset.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrStackVariableDescriptor {
|
||||
|
||||
@ -6,9 +6,13 @@ pub mod ir_block;
|
||||
pub mod ir_call;
|
||||
pub mod ir_expression;
|
||||
pub mod ir_function;
|
||||
pub mod ir_get_field_ref;
|
||||
pub mod ir_get_field_ref_mut;
|
||||
pub mod ir_multiply;
|
||||
pub mod ir_operation;
|
||||
pub mod ir_parameter;
|
||||
pub mod ir_parameter_or_variable;
|
||||
pub mod ir_read_field;
|
||||
pub mod ir_return;
|
||||
pub mod ir_set_field;
|
||||
pub mod ir_statement;
|
||||
|
||||
@ -14,10 +14,7 @@ impl CallableSymbol {
|
||||
pub fn return_type_info(&self) -> TypeInfo {
|
||||
match self {
|
||||
CallableSymbol::Function(function) => function.borrow().return_type_info().clone(),
|
||||
CallableSymbol::Class(class_symbol) => {
|
||||
// At the language level, constructors "return" an instance of their type
|
||||
TypeInfo::ClassInstance(class_symbol.clone())
|
||||
}
|
||||
CallableSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
use crate::ast::ir_builder::IrBuilder;
|
||||
use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_get_field_ref::IrGetFieldRef;
|
||||
use crate::ir::ir_operation::IrOperation;
|
||||
use crate::ir::ir_read_field::IrReadField;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
@ -33,15 +41,62 @@ impl ExpressibleSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ir_expression(&self) -> IrExpression {
|
||||
pub fn ir_expression(&self, builder: &mut IrBuilder) -> IrExpression {
|
||||
match self {
|
||||
ExpressibleSymbol::Class(class_symbol) => {
|
||||
todo!()
|
||||
}
|
||||
ExpressibleSymbol::Field(field_symbol) => {
|
||||
// this, unfortunately, is going to need more context, because fields live longer
|
||||
// than function calls
|
||||
todo!()
|
||||
// This following should work because blocks are flat in the ir; if a variable is
|
||||
// defined in the ir block from this point forward, it's available to all subsequent
|
||||
// blocks.
|
||||
if !builder
|
||||
.field_pointer_variables()
|
||||
.contains_key(field_symbol.borrow().declared_name())
|
||||
{
|
||||
let field_ref_variable = IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
builder.current_block().id(),
|
||||
field_symbol.borrow().type_info(),
|
||||
);
|
||||
let as_rc = Rc::new(RefCell::new(field_ref_variable));
|
||||
let to_insert = as_rc.clone();
|
||||
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
|
||||
builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Assign(IrAssign::new(
|
||||
as_rc,
|
||||
IrOperation::GetFieldRef(IrGetFieldRef::new(
|
||||
self_parameter_or_variable.clone(),
|
||||
field_symbol.borrow().field_index(),
|
||||
)),
|
||||
)));
|
||||
builder
|
||||
.field_pointer_variables_mut()
|
||||
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
|
||||
}
|
||||
// now we need to read the field into a variable and return an expression pointing
|
||||
// to that variable
|
||||
let read_destination = IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
builder.current_block().id(),
|
||||
field_symbol.borrow().type_info(),
|
||||
);
|
||||
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
|
||||
let ir_read_field = IrReadField::new(
|
||||
builder
|
||||
.field_pointer_variables()
|
||||
.get(field_symbol.borrow().declared_name())
|
||||
.unwrap()
|
||||
.clone(),
|
||||
);
|
||||
builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Assign(IrAssign::new(
|
||||
read_destination_as_rc.clone(),
|
||||
IrOperation::ReadField(ir_read_field),
|
||||
)));
|
||||
IrExpression::Variable(read_destination_as_rc)
|
||||
}
|
||||
ExpressibleSymbol::Function(_) => {
|
||||
panic!("Cannot get ir_variable for FunctionSymbol");
|
||||
|
||||
@ -7,26 +7,26 @@ use std::rc::Rc;
|
||||
pub struct ParameterSymbol {
|
||||
declared_name: Rc<str>,
|
||||
declared_name_source_range: SourceRange,
|
||||
type_info: TypeInfo,
|
||||
type_info: Option<TypeInfo>,
|
||||
ir_parameter: Option<Rc<IrParameter>>,
|
||||
}
|
||||
|
||||
impl ParameterSymbol {
|
||||
pub fn new(
|
||||
declared_name: &Rc<str>,
|
||||
declared_name_source_range: SourceRange,
|
||||
type_info: TypeInfo,
|
||||
) -> Self {
|
||||
pub fn new(declared_name: &Rc<str>, declared_name_source_range: SourceRange) -> Self {
|
||||
Self {
|
||||
declared_name: declared_name.clone(),
|
||||
declared_name_source_range,
|
||||
type_info,
|
||||
type_info: None,
|
||||
ir_parameter: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
||||
self.type_info = Some(type_info);
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
&self.type_info
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn set_ir_parameter(&mut self, ir_parameter: Rc<IrParameter>) {
|
||||
|
||||
@ -4,26 +4,4 @@ use std::rc::Rc;
|
||||
|
||||
pub enum TypeSymbol {
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Primitive(PrimitiveTypeSymbol),
|
||||
}
|
||||
|
||||
pub enum PrimitiveTypeSymbol {
|
||||
Any,
|
||||
Int,
|
||||
Double,
|
||||
String,
|
||||
Void,
|
||||
}
|
||||
|
||||
impl PrimitiveTypeSymbol {
|
||||
pub fn try_from_declared_name(declared_name: &str) -> Option<PrimitiveTypeSymbol> {
|
||||
match declared_name {
|
||||
"Any" => Some(PrimitiveTypeSymbol::Any),
|
||||
"Int" => Some(PrimitiveTypeSymbol::Int),
|
||||
"Double" => Some(PrimitiveTypeSymbol::Double),
|
||||
"String" => Some(PrimitiveTypeSymbol::String),
|
||||
"Void" => Some(PrimitiveTypeSymbol::Void),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol::type_symbol::TypeSymbol;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
@ -39,16 +41,25 @@ impl Display for TypeInfo {
|
||||
}
|
||||
|
||||
impl TypeInfo {
|
||||
// This is very naive but works for now
|
||||
#[deprecated]
|
||||
pub fn from_declared_name(declared_name: &str) -> Self {
|
||||
pub fn from_declared_name(
|
||||
declared_name: &str,
|
||||
scope_id: usize,
|
||||
symbol_table: &SymbolTable,
|
||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||
) -> Option<Self> {
|
||||
match declared_name {
|
||||
"Any" => TypeInfo::Any,
|
||||
"Int" => TypeInfo::Integer,
|
||||
"Double" => TypeInfo::Double,
|
||||
"String" => TypeInfo::String,
|
||||
"Void" => TypeInfo::Void,
|
||||
_ => panic!("Unknown type: {}", declared_name),
|
||||
"Any" => Some(TypeInfo::Any),
|
||||
"Int" => Some(TypeInfo::Integer),
|
||||
"Double" => Some(TypeInfo::Double),
|
||||
"String" => Some(TypeInfo::String),
|
||||
"Void" => Some(TypeInfo::Void),
|
||||
"Self" => Some(TypeInfo::ClassInstance(class_context.unwrap().clone())),
|
||||
_ => match symbol_table.find_type_symbol(scope_id, declared_name) {
|
||||
None => None,
|
||||
Some(type_symbol) => match type_symbol {
|
||||
TypeSymbol::Class(class_symbol) => Some(TypeInfo::ClassInstance(class_symbol)),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,8 +18,18 @@ pub enum Instruction {
|
||||
InvokePlatformStatic(FunctionName, ArgCount),
|
||||
|
||||
Allocate(ClassFqn, Location),
|
||||
GetField(Location, FieldIndex, Location),
|
||||
SetField(Location, FieldIndex, SetFieldOperand),
|
||||
|
||||
/// (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),
|
||||
@ -73,11 +83,26 @@ impl Display for Instruction {
|
||||
Instruction::Allocate(class_fqn, location) => {
|
||||
write!(f, "alloc {}, {}", class_fqn, location)
|
||||
}
|
||||
Instruction::GetField(source, field_index, destination) => {
|
||||
write!(f, "getf {}.{}, {}", source, field_index, destination)
|
||||
|
||||
Instruction::GetFieldPointer(self_location, field_index, destination) => {
|
||||
write!(
|
||||
f,
|
||||
"getf &{}.{}, {}",
|
||||
self_location, field_index, destination
|
||||
)
|
||||
}
|
||||
Instruction::SetField(target_location, field_index, operand) => {
|
||||
write!(f, "setf {}.{}, {}", target_location, field_index, operand)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,63 +0,0 @@
|
||||
use crate::instruction::{AddOperand, MultiplyOperand, SubtractOperand};
|
||||
use crate::vm::CallFrame;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::value::Value;
|
||||
use crate::vm::value_util::{load_constant_value, load_value};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn add_operand_to_value(
|
||||
add_operand: &AddOperand,
|
||||
registers: &[Value],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match add_operand {
|
||||
AddOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
)
|
||||
.clone(),
|
||||
AddOperand::Int(i) => Value::Int(*i),
|
||||
AddOperand::Double(d) => Value::Double(*d),
|
||||
AddOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
SubtractOperand::Double(d) => Value::Double(*d),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiply_operand_to_value(
|
||||
multiply_operand: &MultiplyOperand,
|
||||
registers: &[Value],
|
||||
current_frame: &CallFrame,
|
||||
) -> Value {
|
||||
match multiply_operand {
|
||||
MultiplyOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
)
|
||||
.clone(),
|
||||
MultiplyOperand::Int(i) => Value::Int(*i),
|
||||
MultiplyOperand::Double(d) => Value::Double(*d),
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,25 @@
|
||||
use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand};
|
||||
use crate::instruction::Instruction;
|
||||
use crate::platform_function::PlatformFunction;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::function::Function;
|
||||
use crate::vm::instruction_helpers::{
|
||||
add_operand_to_value, multiply_operand_to_value, subtract_operand_to_value,
|
||||
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,
|
||||
};
|
||||
use crate::vm::util::*;
|
||||
use crate::vm::value::Value;
|
||||
use crate::vm::value_util::*;
|
||||
use std::collections::HashMap;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod constant;
|
||||
pub mod function;
|
||||
mod instruction_helpers;
|
||||
pub mod object;
|
||||
pub mod operand;
|
||||
mod operand_helpers;
|
||||
mod util;
|
||||
pub mod value;
|
||||
mod value_util;
|
||||
|
||||
pub struct DvmContext {
|
||||
functions: HashMap<Rc<str>, Function>,
|
||||
@ -61,7 +65,7 @@ pub struct CallFrame<'a> {
|
||||
function: &'a Function,
|
||||
instructions: &'a Vec<Instruction>,
|
||||
ip: usize,
|
||||
stack: Vec<Value>,
|
||||
stack: Vec<Operand>,
|
||||
fp: usize,
|
||||
return_value: Option<Value>,
|
||||
}
|
||||
@ -94,11 +98,11 @@ impl<'a> CallFrame<'a> {
|
||||
self.ip += 1;
|
||||
}
|
||||
|
||||
fn stack(&self) -> &[Value] {
|
||||
fn stack(&self) -> &[Operand] {
|
||||
&self.stack
|
||||
}
|
||||
|
||||
fn stack_mut(&mut self) -> &mut Vec<Value> {
|
||||
fn stack_mut(&mut self) -> &mut Vec<Operand> {
|
||||
&mut self.stack
|
||||
}
|
||||
|
||||
@ -171,7 +175,7 @@ impl<'a> CallStack<'a> {
|
||||
|
||||
pub fn call<'a>(
|
||||
context: &'a DvmContext,
|
||||
registers: &mut Vec<Value>,
|
||||
registers: &mut Vec<Operand>,
|
||||
call_stack: &mut CallStack<'a>,
|
||||
function_name: &str,
|
||||
arguments: &[Value],
|
||||
@ -191,7 +195,10 @@ pub fn call<'a>(
|
||||
|
||||
// put each arg on the stack
|
||||
for argument in arguments {
|
||||
call_stack.top_mut().stack_mut().push(argument.clone());
|
||||
call_stack
|
||||
.top_mut()
|
||||
.stack_mut()
|
||||
.push(Operand::Value(argument.clone()));
|
||||
}
|
||||
|
||||
// set fp for this function
|
||||
@ -200,7 +207,7 @@ pub fn call<'a>(
|
||||
// ensure enough stack space
|
||||
call_stack.top_mut().stack_mut().resize(
|
||||
arguments.len() + (function.stack_size() as usize),
|
||||
Value::Null,
|
||||
Operand::Null,
|
||||
);
|
||||
|
||||
// container for final return value
|
||||
@ -219,41 +226,21 @@ pub fn call<'a>(
|
||||
Instruction::Move(source, destination) => {
|
||||
// move a value to a destination
|
||||
// could be a copy or an immediate
|
||||
let value = match source {
|
||||
MoveOperand::Location(location) => load_value(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
location,
|
||||
)
|
||||
.clone(),
|
||||
MoveOperand::Int(i) => Value::Int(*i),
|
||||
MoveOperand::Double(d) => Value::Double(*d),
|
||||
MoveOperand::String(constant_name) => {
|
||||
load_constant_value(context.constants(), constant_name)
|
||||
}
|
||||
};
|
||||
let value =
|
||||
move_operand_to_value(source, registers, call_stack.top(), context.constants());
|
||||
put_value(registers, call_stack.top_mut(), destination, value);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
/* Push instructions */
|
||||
Instruction::Push(operand) => {
|
||||
let value = match operand {
|
||||
PushOperand::Location(location) => load_value(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
location,
|
||||
)
|
||||
.clone(),
|
||||
PushOperand::Double(d) => Value::Double(*d),
|
||||
PushOperand::Int(i) => Value::Int(*i),
|
||||
PushOperand::String(constant_name) => {
|
||||
load_constant_value(context.constants(), constant_name)
|
||||
}
|
||||
};
|
||||
call_stack.top_mut().stack_mut().push(value);
|
||||
let value = push_operand_to_value(
|
||||
operand,
|
||||
registers,
|
||||
call_stack.top(),
|
||||
context.constants(),
|
||||
);
|
||||
call_stack.top_mut().stack_mut().push(Operand::Value(value));
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
@ -265,8 +252,13 @@ pub fn call<'a>(
|
||||
.expect(&format!("Function {} not found", function_name));
|
||||
|
||||
// get args
|
||||
let mut args =
|
||||
call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec();
|
||||
// this isn't perfect (yet), but for now it works and satisfies the borrow checkers
|
||||
let mut args = call_stack.top().stack()
|
||||
[call_stack.top().stack().len() - arg_count..]
|
||||
.iter()
|
||||
.map(|operand| operand.unwrap_value().clone())
|
||||
.map(|value| Operand::Value(value))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// save registers
|
||||
for register in registers.iter_mut() {
|
||||
@ -287,7 +279,7 @@ pub fn call<'a>(
|
||||
call_stack
|
||||
.top_mut()
|
||||
.stack_mut()
|
||||
.resize(arg_count + (function.stack_size() as usize), Value::Null);
|
||||
.resize(arg_count + (function.stack_size() as usize), Operand::Null);
|
||||
|
||||
// set fp for callee frame
|
||||
let callee_frame = call_stack.top_mut();
|
||||
@ -300,14 +292,22 @@ pub fn call<'a>(
|
||||
.get(function_name)
|
||||
.expect(&format!("Platform function {} not found", function_name));
|
||||
|
||||
let args = &call_stack.top().stack()[call_stack.top().stack().len() - arg_count..];
|
||||
let arg_operands =
|
||||
&call_stack.top().stack()[call_stack.top().stack().len() - arg_count..];
|
||||
let args = arg_operands
|
||||
.iter()
|
||||
.map(|operand| operand.unwrap_value().clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let result = platform_function(args);
|
||||
let result = platform_function(&args);
|
||||
match result {
|
||||
Ok(return_value) => {
|
||||
// push return value to top of caller stack if it's not null
|
||||
if !matches!(return_value, Value::Null) {
|
||||
call_stack.top_mut().stack_mut().push(return_value);
|
||||
call_stack
|
||||
.top_mut()
|
||||
.stack_mut()
|
||||
.push(Operand::Value(return_value));
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
@ -327,18 +327,77 @@ pub fn call<'a>(
|
||||
todo!()
|
||||
}
|
||||
|
||||
Instruction::GetField(source, field_index, destination) => {
|
||||
// let object = load_value(...).unwrap_object();
|
||||
// let field_value = object.fields()[field_index];
|
||||
// put_value(..., destination, field_value.clone());
|
||||
todo!()
|
||||
Instruction::GetFieldPointer(self_location, field_index, destination) => {
|
||||
let object = load_value(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
self_location,
|
||||
)
|
||||
.unwrap_object()
|
||||
.clone();
|
||||
let field_ref = ptr::from_ref(&object.borrow_mut().fields_mut()[*field_index]);
|
||||
put_operand(
|
||||
registers,
|
||||
call_stack.top_mut(),
|
||||
destination,
|
||||
Operand::FieldPointer(field_ref),
|
||||
);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
Instruction::SetField(target, field_index, operand) => {
|
||||
// let new_value = to_value(operand);
|
||||
// let object = load_value(... target).unwrap_object();
|
||||
// object.fields_mut()[field_index] = new_value;
|
||||
todo!()
|
||||
Instruction::GetFieldPointerMut(self_location, field_index, destination) => {
|
||||
let object = load_value(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
self_location,
|
||||
)
|
||||
.unwrap_object()
|
||||
.clone();
|
||||
let field_ref = ptr::from_mut(&mut object.borrow_mut().fields_mut()[*field_index]);
|
||||
put_operand(
|
||||
registers,
|
||||
call_stack.top_mut(),
|
||||
destination,
|
||||
Operand::FieldPointerMut(field_ref),
|
||||
);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
Instruction::ReadField(field_pointer_location, destination) => {
|
||||
let field_pointer = load_operand(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
field_pointer_location,
|
||||
)
|
||||
.unwrap_field_pointer();
|
||||
// clone is very important, otherwise we mess up the self object!
|
||||
let value = unsafe { field_pointer.read() }.clone();
|
||||
put_value(registers, call_stack.top_mut(), destination, value);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
Instruction::SetField(field_point_mut_location, operand) => {
|
||||
let fp = call_stack.top().fp(); // borrow checker :)
|
||||
let field_pointer_mut = load_operand_mut(
|
||||
registers,
|
||||
call_stack.top_mut().stack_mut(),
|
||||
fp,
|
||||
field_point_mut_location,
|
||||
)
|
||||
.unwrap_field_pointer_mut();
|
||||
let value = set_field_operand_to_value(
|
||||
operand,
|
||||
registers,
|
||||
call_stack.top(),
|
||||
context.constants(),
|
||||
);
|
||||
unsafe {
|
||||
field_pointer_mut.write(value);
|
||||
}
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
/* Add instructions */
|
||||
@ -442,27 +501,19 @@ pub fn call<'a>(
|
||||
Instruction::Pop(maybe_location) => {
|
||||
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
||||
if let Some(location) = maybe_location {
|
||||
put_value(registers, call_stack.top_mut(), location, value);
|
||||
put_operand(registers, call_stack.top_mut(), location, value);
|
||||
}
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
/* Return instructions */
|
||||
Instruction::SetReturnValue(return_operand) => {
|
||||
let value = match return_operand {
|
||||
ReturnOperand::Location(location) => load_value(
|
||||
registers,
|
||||
call_stack.top().stack(),
|
||||
call_stack.top().fp(),
|
||||
location,
|
||||
)
|
||||
.clone(),
|
||||
ReturnOperand::Int(i) => Value::Int(*i),
|
||||
ReturnOperand::Double(d) => Value::Double(*d),
|
||||
ReturnOperand::String(constant_name) => {
|
||||
load_constant_value(context.constants(), constant_name)
|
||||
}
|
||||
};
|
||||
let value = return_operand_to_value(
|
||||
return_operand,
|
||||
registers,
|
||||
call_stack.top(),
|
||||
context.constants(),
|
||||
);
|
||||
call_stack.top_mut().set_return_value(value);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
@ -484,7 +535,7 @@ pub fn call<'a>(
|
||||
// push return value if some
|
||||
if let Some(return_value) = callee.take_return_value() {
|
||||
// n.b. callee
|
||||
caller.stack_mut().push(return_value);
|
||||
caller.stack_mut().push(Operand::Value(return_value));
|
||||
}
|
||||
} else {
|
||||
// callee is the bottommost frame ("main" or whatever was called)
|
||||
|
||||
@ -7,6 +7,16 @@ pub struct Object {
|
||||
fields: [Value],
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn fields(&self) -> &[Value] {
|
||||
&self.fields
|
||||
}
|
||||
|
||||
pub fn fields_mut(&mut self) -> &mut [Value] {
|
||||
&mut self.fields
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ObjectHeader {
|
||||
field_count: usize,
|
||||
}
|
||||
|
||||
51
dvm-lib/src/vm/operand.rs
Normal file
51
dvm-lib/src/vm/operand.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use crate::vm::value::Value;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Operand {
|
||||
Value(Value),
|
||||
FieldPointer(*const Value),
|
||||
FieldPointerMut(*mut Value),
|
||||
Null,
|
||||
}
|
||||
|
||||
impl Operand {
|
||||
pub fn unwrap_value(&self) -> &Value {
|
||||
match self {
|
||||
Operand::Value(value) => value,
|
||||
_ => panic!("Attempt to unwrap {:?} as Value", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_field_pointer(&self) -> *const Value {
|
||||
match self {
|
||||
Operand::FieldPointer(p) => *p,
|
||||
_ => panic!("Attempt to unwrap {:?} as FieldPointer", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_field_pointer_mut(&mut self) -> *mut Value {
|
||||
match self {
|
||||
Operand::FieldPointerMut(p) => *p,
|
||||
_ => panic!("Attempt to unwrap {:?} as FieldPointerMut", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Operand {
|
||||
fn default() -> Self {
|
||||
Operand::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Operand {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Operand::Value(value) => Operand::Value(Value::clone(value)),
|
||||
Operand::FieldPointer(field_ref) => Operand::FieldPointer(*field_ref),
|
||||
Operand::FieldPointerMut(_) => {
|
||||
panic!("Cannot clone FieldRefMut")
|
||||
}
|
||||
Operand::Null => Operand::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
140
dvm-lib/src/vm/operand_helpers.rs
Normal file
140
dvm-lib/src/vm/operand_helpers.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use crate::instruction::{
|
||||
AddOperand, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SetFieldOperand,
|
||||
SubtractOperand,
|
||||
};
|
||||
use crate::vm::CallFrame;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::operand::Operand;
|
||||
use crate::vm::util::{load_constant_value, load_value};
|
||||
use crate::vm::value::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn move_operand_to_value(
|
||||
move_operand: &MoveOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match move_operand {
|
||||
MoveOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
MoveOperand::Int(i) => Value::Int(*i),
|
||||
MoveOperand::Double(d) => Value::Double(*d),
|
||||
MoveOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_operand_to_value(
|
||||
push_operand: &PushOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match push_operand {
|
||||
PushOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
PushOperand::Double(d) => Value::Double(*d),
|
||||
PushOperand::Int(i) => Value::Int(*i),
|
||||
PushOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_operand_to_value(
|
||||
add_operand: &AddOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match add_operand {
|
||||
AddOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
AddOperand::Int(i) => Value::Int(*i),
|
||||
AddOperand::Double(d) => Value::Double(*d),
|
||||
AddOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subtract_operand_to_value(
|
||||
subtract_operand: &SubtractOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
) -> Value {
|
||||
match subtract_operand {
|
||||
SubtractOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
SubtractOperand::Int(i) => Value::Int(*i),
|
||||
SubtractOperand::Double(d) => Value::Double(*d),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiply_operand_to_value(
|
||||
multiply_operand: &MultiplyOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
) -> Value {
|
||||
match multiply_operand {
|
||||
MultiplyOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
MultiplyOperand::Int(i) => Value::Int(*i),
|
||||
MultiplyOperand::Double(d) => Value::Double(*d),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn return_operand_to_value(
|
||||
return_operand: &ReturnOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match return_operand {
|
||||
ReturnOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
ReturnOperand::Int(i) => Value::Int(*i),
|
||||
ReturnOperand::Double(d) => Value::Double(*d),
|
||||
ReturnOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_field_operand_to_value(
|
||||
set_field_operand: &SetFieldOperand,
|
||||
registers: &[Operand],
|
||||
current_frame: &CallFrame,
|
||||
constants: &HashMap<Rc<str>, Constant>,
|
||||
) -> Value {
|
||||
match set_field_operand {
|
||||
SetFieldOperand::Location(location) => load_value(
|
||||
registers,
|
||||
current_frame.stack(),
|
||||
current_frame.fp(),
|
||||
location,
|
||||
),
|
||||
SetFieldOperand::Int(i) => Value::Int(*i),
|
||||
SetFieldOperand::Double(d) => Value::Double(*d),
|
||||
SetFieldOperand::String(constant_name) => load_constant_value(constants, constant_name),
|
||||
}
|
||||
}
|
||||
90
dvm-lib/src/vm/util.rs
Normal file
90
dvm-lib/src/vm/util.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::instruction::{ConstantName, Location};
|
||||
use crate::vm::CallFrame;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::operand::Operand;
|
||||
use crate::vm::value::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[inline]
|
||||
fn calculate_from_offset(fp: usize, offset: isize) -> usize {
|
||||
fp.checked_add_signed(offset).expect(&format!(
|
||||
"Overflow when adding offset {} to fp {}",
|
||||
offset, fp
|
||||
))
|
||||
}
|
||||
|
||||
pub fn load_operand<'a>(
|
||||
registers: &'a [Operand],
|
||||
stack: &'a [Operand],
|
||||
fp: usize,
|
||||
location: &Location,
|
||||
) -> &'a Operand {
|
||||
match location {
|
||||
Location::Register(register) => ®isters[*register],
|
||||
Location::StackFrameOffset(offset) => &stack[calculate_from_offset(fp, *offset)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_operand_mut<'a>(
|
||||
registers: &'a mut [Operand],
|
||||
stack: &'a mut [Operand],
|
||||
fp: usize,
|
||||
location: &Location,
|
||||
) -> &'a mut Operand {
|
||||
match location {
|
||||
Location::Register(register) => &mut registers[*register],
|
||||
Location::StackFrameOffset(offset) => &mut stack[calculate_from_offset(fp, *offset)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_value(
|
||||
registers: &[Operand],
|
||||
stack: &[Operand],
|
||||
fp: usize,
|
||||
location: &Location,
|
||||
) -> Value {
|
||||
load_operand(registers, stack, fp, location)
|
||||
.unwrap_value()
|
||||
.clone()
|
||||
}
|
||||
|
||||
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_operand(
|
||||
registers: &mut Vec<Operand>,
|
||||
current_frame: &mut CallFrame,
|
||||
destination: &Location,
|
||||
operand: Operand,
|
||||
) {
|
||||
match destination {
|
||||
Location::Register(register) => {
|
||||
registers[*register] = operand;
|
||||
}
|
||||
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] = operand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put_value(
|
||||
registers: &mut Vec<Operand>,
|
||||
current_frame: &mut CallFrame,
|
||||
destination: &Location,
|
||||
value: Value,
|
||||
) {
|
||||
put_operand(registers, current_frame, destination, Operand::Value(value));
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
use crate::vm::object::Object;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -36,6 +38,14 @@ impl Value {
|
||||
_ => panic!("Attempt to unwrap String; found {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_object(&self) -> &Rc<RefCell<Object>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn unwrap_object_mut(&mut self) -> &mut Rc<RefCell<Object>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ mod e2e_tests {
|
||||
use dmc_lib::symbol_table::SymbolTable;
|
||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||
use dvm_lib::vm::function::Function;
|
||||
use dvm_lib::vm::operand::Operand;
|
||||
use dvm_lib::vm::value::Value;
|
||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||
use std::rc::Rc;
|
||||
@ -90,7 +91,7 @@ mod e2e_tests {
|
||||
function_name: &str,
|
||||
arguments: &[Value],
|
||||
) -> Option<Value> {
|
||||
let mut registers: Vec<Value> = vec![Value::Null; REGISTER_COUNT];
|
||||
let mut registers: Vec<Operand> = vec![Operand::Null; REGISTER_COUNT];
|
||||
let mut call_stack = CallStack::new();
|
||||
|
||||
call(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user