Compare commits
2 Commits
89f519c45f
...
75dcca0002
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75dcca0002 | ||
|
|
efecd6b9c8 |
@ -133,8 +133,12 @@ fn compile_expression(
|
||||
"__repl",
|
||||
SourceRange::new(0, 0),
|
||||
false,
|
||||
expression.type_info().clone(), // dubious
|
||||
)));
|
||||
|
||||
fake_function_symbol
|
||||
.borrow_mut()
|
||||
.set_return_type_info(expression.type_info().clone());
|
||||
|
||||
let mut ir_function = IrFunction::new(
|
||||
fake_function_symbol,
|
||||
&[],
|
||||
|
||||
@ -2,7 +2,8 @@ use crate::ast::field::Field;
|
||||
use crate::ast::function::Function;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Class {
|
||||
@ -32,16 +33,142 @@ impl Class {
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// 1. insert class symbol
|
||||
// 2. gather fields
|
||||
// 3. gather functions
|
||||
todo!()
|
||||
let to_insert = ClassSymbol::new(
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
false,
|
||||
);
|
||||
|
||||
symbol_table
|
||||
.insert_class_symbol(to_insert)
|
||||
.map_err(|e| match e {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||
vec![
|
||||
Diagnostic::new(
|
||||
&format!(
|
||||
"Symbol {} already declared in current scope.",
|
||||
already_declared.symbol().borrow().declared_name(),
|
||||
),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
]
|
||||
}
|
||||
})?;
|
||||
|
||||
// 2. push scope
|
||||
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
||||
|
||||
// 3. gather fields
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.gather_declared_names(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if !fields_diagnostics.is_empty() {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
// 4. gather functions
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.gather_declared_names(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if !functions_diagnostics.is_empty() {
|
||||
return Err(functions_diagnostics);
|
||||
}
|
||||
|
||||
// 5. pop scope
|
||||
symbol_table.pop_scope();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
todo!()
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
if !fields_diagnostics.is_empty() {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if functions_diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(functions_diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::parser::parse_compilation_unit;
|
||||
|
||||
#[test]
|
||||
fn name_analysis_no_diagnostics() {
|
||||
let parse_result = parse_compilation_unit(
|
||||
"
|
||||
class Foo
|
||||
mut bar = 42
|
||||
|
||||
fn baz() -> Int
|
||||
bar
|
||||
end
|
||||
end
|
||||
|
||||
class Qux
|
||||
fn foo() -> Foo
|
||||
Foo()
|
||||
end
|
||||
end
|
||||
",
|
||||
);
|
||||
|
||||
let mut compilation_unit = match parse_result {
|
||||
Ok(compilation_unit) => compilation_unit,
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
};
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,9 @@ impl Expression {
|
||||
Expression::Subtract(subtract_expression) => {
|
||||
Some(subtract_expression.to_ir_expression(builder, symbol_table))
|
||||
}
|
||||
Expression::Negative(_) => todo!(),
|
||||
Expression::Negative(negative_expression) => {
|
||||
Some(negative_expression.to_ir(builder, symbol_table))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,12 +4,15 @@ use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct ExternFunction {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: TypeUse,
|
||||
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
||||
}
|
||||
|
||||
impl ExternFunction {
|
||||
@ -24,6 +27,7 @@ impl ExternFunction {
|
||||
declared_name_source_range,
|
||||
parameters,
|
||||
return_type,
|
||||
function_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +45,6 @@ impl ExternFunction {
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
true,
|
||||
self.return_type.to_type_info(),
|
||||
));
|
||||
|
||||
let function_symbol = match insert_result {
|
||||
@ -82,6 +85,16 @@ impl ExternFunction {
|
||||
.borrow_mut()
|
||||
.set_parameters(parameter_symbols);
|
||||
|
||||
self.function_symbol = Some(function_symbol);
|
||||
|
||||
// handle return type
|
||||
match self.return_type.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
symbol_table.pop_scope(); // function scope
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
@ -92,14 +105,29 @@ impl ExternFunction {
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
let mut diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
match self.return_type.check_name_usages(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut return_type_diagnostics) => {
|
||||
diagnostics.append(&mut return_type_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
// set return type info on symbol now that its available
|
||||
self.function_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(self.return_type.to_type_info());
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Field {
|
||||
@ -30,4 +33,51 @@ impl Field {
|
||||
initializer: initializer.map(Box::new),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// 1. insert field symbol
|
||||
let to_insert =
|
||||
FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone());
|
||||
|
||||
symbol_table
|
||||
.insert_field_symbol(to_insert)
|
||||
.map_err(|e| match e {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||
vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Symbol {} already declared in current scope.",
|
||||
already_declared.symbol().borrow().declared_name()
|
||||
),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)]
|
||||
}
|
||||
})?;
|
||||
|
||||
// 2. gather initializer, if present
|
||||
if let Some(initializer) = &mut self.initializer {
|
||||
initializer.gather_declared_names(symbol_table)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
if let Some(type_use) = &mut self.declared_type {
|
||||
type_use.check_name_usages(symbol_table)?;
|
||||
}
|
||||
|
||||
// This is going to get hairy, because users might attempt to use a field in an initializer
|
||||
// (for either this field, or another one) before it's actually initialized. As such, we
|
||||
// need a way to prevent lookup of current class' fields in the initializer.
|
||||
// For now, the following is okay so long as we don't start referencing things in the
|
||||
// initializers.
|
||||
if let Some(initializer) = self.initializer.as_mut() {
|
||||
initializer.check_name_usages(symbol_table)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,15 +58,15 @@ impl Function {
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
return Err(diagnostics);
|
||||
}
|
||||
|
||||
// insert function symbol
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
self.declared_name(),
|
||||
self.declared_name_source_range.clone(),
|
||||
false,
|
||||
self.return_type
|
||||
.as_ref()
|
||||
.map(|return_type| return_type.to_type_info())
|
||||
.unwrap_or(TypeInfo::Void),
|
||||
));
|
||||
|
||||
// get function symbol if successful
|
||||
@ -109,6 +109,16 @@ impl Function {
|
||||
.borrow_mut()
|
||||
.set_parameters(parameter_symbols);
|
||||
|
||||
// return type
|
||||
if let Some(type_use) = &mut self.return_type {
|
||||
match type_use.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name));
|
||||
for statement in &mut self.statements {
|
||||
match statement.gather_declared_names(symbol_table) {
|
||||
@ -142,6 +152,28 @@ impl Function {
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// return type
|
||||
if let Some(type_use) = &mut self.return_type {
|
||||
match type_use.check_name_usages(symbol_table) {
|
||||
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());
|
||||
}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we don't have a given return type, so it's void
|
||||
self.function_symbol.as_mut().unwrap().borrow_mut().set_return_type_info(
|
||||
TypeInfo::Void
|
||||
);
|
||||
}
|
||||
|
||||
// statements
|
||||
for statement in &mut self.statements {
|
||||
match statement.check_name_usages(symbol_table) {
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::ir_builder::IrBuilder;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::ir::ir_assign::IrAssign;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_multiply::IrMultiply;
|
||||
use crate::ir::ir_operation::IrOperation;
|
||||
use crate::ir::ir_statement::IrStatement;
|
||||
use crate::ir::ir_variable::IrVariable;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct NegativeExpression {
|
||||
operand: Box<Expression>,
|
||||
@ -58,6 +67,67 @@ impl NegativeExpression {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression {
|
||||
let operand_as_ir = self
|
||||
.operand
|
||||
.to_ir(builder, symbol_table)
|
||||
.expect("Attempt to negate non-value expression");
|
||||
|
||||
match operand_as_ir {
|
||||
IrExpression::Parameter(parameter) => {
|
||||
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
builder.current_block().id(),
|
||||
parameter.type_info(),
|
||||
)));
|
||||
|
||||
let rhs = match parameter.type_info() {
|
||||
TypeInfo::Integer => IrExpression::Int(-1),
|
||||
TypeInfo::Double => IrExpression::Double(-1.0),
|
||||
_ => panic!("Trying to multiply with a non-integer/double"),
|
||||
};
|
||||
|
||||
let operation =
|
||||
IrOperation::Multiply(IrMultiply::new(IrExpression::Parameter(parameter), rhs));
|
||||
|
||||
let assign = IrAssign::new(destination.clone(), operation);
|
||||
builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Assign(assign));
|
||||
|
||||
IrExpression::Variable(destination)
|
||||
}
|
||||
IrExpression::Variable(variable) => {
|
||||
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
builder.current_block().id(),
|
||||
variable.borrow().type_info(),
|
||||
)));
|
||||
|
||||
let rhs = match variable.borrow().type_info() {
|
||||
TypeInfo::Integer => IrExpression::Int(-1),
|
||||
TypeInfo::Double => IrExpression::Double(-1.0),
|
||||
_ => panic!("Trying to multiply with a non-integer/double"),
|
||||
};
|
||||
|
||||
let operation =
|
||||
IrOperation::Multiply(IrMultiply::new(IrExpression::Variable(variable), rhs));
|
||||
|
||||
let assign = IrAssign::new(destination.clone(), operation);
|
||||
builder
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Assign(assign));
|
||||
|
||||
IrExpression::Variable(destination)
|
||||
}
|
||||
IrExpression::Int(i) => IrExpression::Int(i * -1),
|
||||
IrExpression::Double(d) => IrExpression::Double(d * -1.0),
|
||||
IrExpression::String(_) => {
|
||||
panic!("Attempt to negate IrExpression::String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ impl Parameter {
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
|
||||
// insert parameter symbol
|
||||
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
@ -40,26 +41,32 @@ impl Parameter {
|
||||
match insert_result {
|
||||
Ok(parameter_symbol) => {
|
||||
self.parameter_symbol = Some(parameter_symbol.clone());
|
||||
Ok(parameter_symbol)
|
||||
}
|
||||
Err(symbol_insert_error) => match symbol_insert_error {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Parameter {} already declared.",
|
||||
already_declared.symbol().borrow().declared_name()
|
||||
),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)]),
|
||||
},
|
||||
Err(symbol_insert_error) => {
|
||||
return match symbol_insert_error {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||
Err(vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Parameter {} already declared.",
|
||||
already_declared.symbol().borrow().declared_name()
|
||||
),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)])
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// type use
|
||||
self.type_use.gather_declared_names(symbol_table)?;
|
||||
|
||||
Ok(self.parameter_symbol.clone().unwrap())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
_symbol_table: &SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
Ok(()) // no-op for now
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.type_use.check_name_usages(symbol_table)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::type_symbol::{PrimitiveTypeSymbol, TypeSymbol};
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct TypeUse {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
scope_id: Option<usize>,
|
||||
type_symbol: Option<TypeSymbol>,
|
||||
}
|
||||
|
||||
impl TypeUse {
|
||||
@ -11,6 +16,8 @@ impl TypeUse {
|
||||
Self {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
scope_id: None,
|
||||
type_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +25,47 @@ impl TypeUse {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
self.scope_id = Some(symbol_table.current_scope_id());
|
||||
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));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vec![
|
||||
Diagnostic::new(
|
||||
&format!("Unable to resolve symbol {}", self.declared_name),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_type_info(&self) -> TypeInfo {
|
||||
TypeInfo::from_declared_name(self.declared_name())
|
||||
match self.type_symbol.as_ref().unwrap() {
|
||||
TypeSymbol::Class(class_symbol) => TypeInfo::Class(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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +101,10 @@ impl Assemble for IrAssign {
|
||||
let (left, right) = ir_subtract.operand_pair();
|
||||
builder.push(Instruction::Subtract(left, right, destination));
|
||||
}
|
||||
IrOperation::Multiply(ir_multiply) => {
|
||||
let (left, right) = ir_multiply.operand_pair();
|
||||
builder.push(Instruction::Multiply(left, right, destination));
|
||||
}
|
||||
IrOperation::Call(ir_call) => {
|
||||
ir_call.assemble(builder, constants_table);
|
||||
builder.push(Instruction::Pop(Some(destination)));
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::ir::ir_variable::{
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use crate::type_info::TypeInfo;
|
||||
use dvm_lib::instruction::{
|
||||
AddOperand, Location, MoveOperand, PushOperand, ReturnOperand, SubtractOperand,
|
||||
AddOperand, Location, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SubtractOperand,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -149,6 +149,27 @@ impl IrExpression {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn multiply_operand(&self) -> MultiplyOperand {
|
||||
match self {
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||
}
|
||||
IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() {
|
||||
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||
MultiplyOperand::Location(Location::Register(vr_variable.assigned_register()))
|
||||
}
|
||||
IrVariableDescriptor::Stack(stack_variable) => {
|
||||
MultiplyOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
||||
}
|
||||
},
|
||||
IrExpression::Int(i) => MultiplyOperand::Int(*i),
|
||||
IrExpression::Double(d) => MultiplyOperand::Double(*d),
|
||||
IrExpression::String(_) => {
|
||||
panic!("Attempt to multiply with a string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
||||
match self {
|
||||
IrExpression::Parameter(ir_parameter) => {
|
||||
|
||||
67
dmc-lib/src/ir/ir_multiply.rs
Normal file
67
dmc-lib/src/ir/ir_multiply.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
use dvm_lib::instruction::MultiplyOperand;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
pub struct IrMultiply {
|
||||
left: Box<IrExpression>,
|
||||
right: Box<IrExpression>,
|
||||
}
|
||||
|
||||
impl IrMultiply {
|
||||
pub fn new(left: IrExpression, right: IrExpression) -> Self {
|
||||
Self {
|
||||
left: left.into(),
|
||||
right: right.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operand_pair(&self) -> (MultiplyOperand, MultiplyOperand) {
|
||||
(self.left.multiply_operand(), self.right.multiply_operand())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IrMultiply {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} * {}", self.left, self.right)
|
||||
}
|
||||
}
|
||||
|
||||
impl VrUser for IrMultiply {
|
||||
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
[&self.left, &self.right]
|
||||
.iter()
|
||||
.flat_map(|ir_expression| ir_expression.vr_definitions())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||
[&self.left, &self.right]
|
||||
.iter()
|
||||
.flat_map(|ir_expression| ir_expression.vr_uses())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||
[&mut self.left, &mut self.right]
|
||||
.iter_mut()
|
||||
.for_each(|ir_expression| ir_expression.propagate_spills(spills));
|
||||
}
|
||||
|
||||
fn propagate_register_assignments(
|
||||
&mut self,
|
||||
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||
) {
|
||||
[&mut self.left, &mut self.right]
|
||||
.iter_mut()
|
||||
.for_each(|ir_expression| ir_expression.propagate_register_assignments(assignments));
|
||||
}
|
||||
|
||||
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {
|
||||
[&mut self.left, &mut self.right]
|
||||
.iter_mut()
|
||||
.for_each(|ir_expression| ir_expression.propagate_stack_offsets(counter));
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::ir::ir_add::IrAdd;
|
||||
use crate::ir::ir_call::IrCall;
|
||||
use crate::ir::ir_expression::IrExpression;
|
||||
use crate::ir::ir_multiply::IrMultiply;
|
||||
use crate::ir::ir_subtract::IrSubtract;
|
||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||
@ -11,6 +12,7 @@ pub enum IrOperation {
|
||||
Load(IrExpression),
|
||||
Add(IrAdd),
|
||||
Subtract(IrSubtract),
|
||||
Multiply(IrMultiply),
|
||||
Call(IrCall),
|
||||
}
|
||||
|
||||
@ -26,6 +28,9 @@ impl Display for IrOperation {
|
||||
IrOperation::Subtract(ir_subtract) => {
|
||||
write!(f, "{}", ir_subtract)
|
||||
}
|
||||
IrOperation::Multiply(ir_multiply) => {
|
||||
write!(f, "{}", ir_multiply)
|
||||
}
|
||||
IrOperation::Call(ir_call) => {
|
||||
write!(f, "{}", ir_call)
|
||||
}
|
||||
@ -39,6 +44,7 @@ impl VrUser for IrOperation {
|
||||
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
||||
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
||||
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(),
|
||||
IrOperation::Multiply(ir_multiply) => ir_multiply.vr_definitions(),
|
||||
IrOperation::Call(ir_call) => ir_call.vr_definitions(),
|
||||
}
|
||||
}
|
||||
@ -48,6 +54,7 @@ impl VrUser for IrOperation {
|
||||
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
||||
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
||||
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
|
||||
IrOperation::Multiply(ir_multiply) => ir_multiply.vr_uses(),
|
||||
IrOperation::Call(ir_call) => ir_call.vr_uses(),
|
||||
}
|
||||
}
|
||||
@ -63,6 +70,9 @@ impl VrUser for IrOperation {
|
||||
IrOperation::Subtract(ir_subtract) => {
|
||||
ir_subtract.propagate_spills(spills);
|
||||
}
|
||||
IrOperation::Multiply(ir_multiply) => {
|
||||
ir_multiply.propagate_spills(spills);
|
||||
}
|
||||
IrOperation::Call(ir_call) => {
|
||||
ir_call.propagate_spills(spills);
|
||||
}
|
||||
@ -83,6 +93,9 @@ impl VrUser for IrOperation {
|
||||
IrOperation::Subtract(ir_subtract) => {
|
||||
ir_subtract.propagate_register_assignments(assignments);
|
||||
}
|
||||
IrOperation::Multiply(ir_multiply) => {
|
||||
ir_multiply.propagate_register_assignments(assignments);
|
||||
}
|
||||
IrOperation::Call(ir_call) => {
|
||||
ir_call.propagate_register_assignments(assignments);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ pub mod ir_block;
|
||||
pub mod ir_call;
|
||||
pub mod ir_expression;
|
||||
pub mod ir_function;
|
||||
pub mod ir_multiply;
|
||||
pub mod ir_operation;
|
||||
pub mod ir_parameter;
|
||||
pub mod ir_return;
|
||||
|
||||
@ -10,7 +10,7 @@ pub struct FunctionSymbol {
|
||||
declared_name_source_range: SourceRange,
|
||||
is_extern: bool,
|
||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||
return_type: TypeInfo,
|
||||
return_type: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl FunctionSymbol {
|
||||
@ -18,27 +18,16 @@ impl FunctionSymbol {
|
||||
declared_name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
is_extern: bool,
|
||||
return_type: TypeInfo,
|
||||
) -> Self {
|
||||
Self {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
is_extern,
|
||||
parameters: None,
|
||||
return_type,
|
||||
return_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(note = "use declared_name")]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
#[deprecated(note = "use declared_name_owned")]
|
||||
pub fn name_owned(&self) -> Rc<str> {
|
||||
self.declared_name.clone()
|
||||
}
|
||||
|
||||
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
||||
self.parameters = Some(parameters);
|
||||
}
|
||||
@ -47,8 +36,12 @@ impl FunctionSymbol {
|
||||
self.parameters.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn set_return_type_info(&mut self, return_type: TypeInfo) {
|
||||
self.return_type = Some(return_type);
|
||||
}
|
||||
|
||||
pub fn return_type_info(&self) -> &TypeInfo {
|
||||
&self.return_type
|
||||
self.return_type.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn is_extern(&self) -> bool {
|
||||
|
||||
@ -6,6 +6,7 @@ pub mod expressible_symbol;
|
||||
pub mod field_symbol;
|
||||
pub mod function_symbol;
|
||||
pub mod parameter_symbol;
|
||||
pub mod type_symbol;
|
||||
pub mod variable_symbol;
|
||||
|
||||
pub trait Symbol {
|
||||
|
||||
29
dmc-lib/src/symbol/type_symbol.rs
Normal file
29
dmc-lib/src/symbol/type_symbol.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use std::cell::RefCell;
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ use crate::scope::function_scope::FunctionScope;
|
||||
use crate::scope::module_scope::ModuleScope;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::type_symbol::TypeSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -134,3 +135,25 @@ pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleS
|
||||
Scope::Block(block_scope) => find_expressible_in_block_by_name(block_scope, name),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option<TypeSymbol> {
|
||||
module_scope
|
||||
.class_symbols()
|
||||
.get(name)
|
||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||
}
|
||||
|
||||
fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
||||
class_scope
|
||||
.class_symbols()
|
||||
.get(name)
|
||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||
}
|
||||
|
||||
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
||||
match scope {
|
||||
Scope::Module(module_scope) => find_type_symbol_in_module(module_scope, name),
|
||||
Scope::Class(class_scope) => find_type_symbol_in_class(class_scope, name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,13 +6,16 @@ use crate::scope::class_scope::ClassScope;
|
||||
use crate::scope::function_scope::FunctionScope;
|
||||
use crate::scope::module_scope::ModuleScope;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::symbol::type_symbol::TypeSymbol;
|
||||
use crate::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::symbol_table::helpers::{
|
||||
find_expressible_symbol, find_in_block_by_name, find_in_class_by_name,
|
||||
find_in_function_by_name, find_in_module_by_name,
|
||||
find_in_function_by_name, find_in_module_by_name, find_type_symbol,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
@ -84,6 +87,72 @@ impl SymbolTable {
|
||||
&mut self.scopes[self.current_scope_id.unwrap()]
|
||||
}
|
||||
|
||||
pub fn insert_class_symbol(
|
||||
&mut self,
|
||||
class_symbol: ClassSymbol,
|
||||
) -> Result<Rc<RefCell<ClassSymbol>>, SymbolInsertError> {
|
||||
let maybe_already_inserted = match self.current_scope() {
|
||||
Scope::Module(module_scope) => {
|
||||
find_in_module_by_name(module_scope, class_symbol.declared_name())
|
||||
}
|
||||
Scope::Class(class_scope) => {
|
||||
find_in_class_by_name(class_scope, class_symbol.declared_name())
|
||||
}
|
||||
_ => panic!("Attempt to insert ClassSymbol in incompatible scope"),
|
||||
};
|
||||
|
||||
if let Some(already_inserted) = maybe_already_inserted {
|
||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
||||
already_inserted,
|
||||
)));
|
||||
}
|
||||
|
||||
let name = class_symbol.declared_name_owned();
|
||||
let as_rc = Rc::new(RefCell::new(class_symbol));
|
||||
let to_return = as_rc.clone();
|
||||
|
||||
match self.current_scope_mut() {
|
||||
Scope::Module(module_scope) => {
|
||||
module_scope.class_symbols_mut().insert(name, as_rc);
|
||||
}
|
||||
Scope::Class(class_scope) => {
|
||||
class_scope.class_symbols_mut().insert(name, as_rc);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(to_return)
|
||||
}
|
||||
|
||||
pub fn insert_field_symbol(
|
||||
&mut self,
|
||||
field_symbol: FieldSymbol,
|
||||
) -> Result<Rc<RefCell<FieldSymbol>>, SymbolInsertError> {
|
||||
let maybe_already_inserted = match self.current_scope() {
|
||||
Scope::Class(class_scope) => {
|
||||
find_in_class_by_name(class_scope, field_symbol.declared_name())
|
||||
}
|
||||
_ => panic!("Attempt to insert FieldSymbol in incompatible scope"),
|
||||
};
|
||||
|
||||
if let Some(already_inserted) = maybe_already_inserted {
|
||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
||||
already_inserted,
|
||||
)));
|
||||
}
|
||||
|
||||
let name = field_symbol.declared_name_owned();
|
||||
let as_rc = Rc::new(RefCell::new(field_symbol));
|
||||
let to_return = as_rc.clone();
|
||||
|
||||
match self.current_scope_mut() {
|
||||
Scope::Class(class_scope) => {
|
||||
class_scope.field_symbols_mut().insert(name, as_rc);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(to_return)
|
||||
}
|
||||
|
||||
pub fn insert_function_symbol(
|
||||
&mut self,
|
||||
function_symbol: FunctionSymbol,
|
||||
@ -198,6 +267,22 @@ impl SymbolTable {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_type_symbol(&self, scope_id: usize, name: &str) -> Option<TypeSymbol> {
|
||||
let mut maybe_scope = self.scopes.get(scope_id);
|
||||
if maybe_scope.is_none() {
|
||||
panic!("Invalid scope_id: {}", scope_id);
|
||||
}
|
||||
while let Some(scope) = maybe_scope {
|
||||
let maybe_type_symbol = find_type_symbol(scope, name);
|
||||
if maybe_type_symbol.is_some() {
|
||||
return maybe_type_symbol;
|
||||
} else {
|
||||
maybe_scope = scope.parent_id().map(|id| &self.scopes[id]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc<RefCell<VariableSymbol>> {
|
||||
match &self.scopes[scope_id] {
|
||||
Scope::Block(block_scope) => block_scope.variable_symbols().get(name).cloned().unwrap(),
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -10,6 +12,7 @@ pub enum TypeInfo {
|
||||
Double,
|
||||
String,
|
||||
Function(Rc<RefCell<FunctionSymbol>>),
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Void,
|
||||
}
|
||||
|
||||
@ -27,6 +30,9 @@ impl Display for TypeInfo {
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
TypeInfo::Class(class_symbol) => {
|
||||
write!(f, "{}", class_symbol.borrow().declared_name())
|
||||
}
|
||||
TypeInfo::Void => write!(f, "Void"),
|
||||
}
|
||||
}
|
||||
@ -34,6 +40,7 @@ impl Display for TypeInfo {
|
||||
|
||||
impl TypeInfo {
|
||||
// This is very naive but works for now
|
||||
#[deprecated]
|
||||
pub fn from_declared_name(declared_name: &str) -> Self {
|
||||
match declared_name {
|
||||
"Any" => TypeInfo::Any,
|
||||
@ -60,6 +67,15 @@ impl TypeInfo {
|
||||
TypeInfo::Function(_) => {
|
||||
unimplemented!("Type matching on Functions not yet supported.")
|
||||
}
|
||||
TypeInfo::Class(class_symbol) => {
|
||||
match other {
|
||||
TypeInfo::Class(other_class_symbol) => {
|
||||
class_symbol.borrow().declared_name()
|
||||
== other_class_symbol.borrow().declared_name() // good enough for now
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
TypeInfo::Void => {
|
||||
matches!(other, TypeInfo::Void)
|
||||
}
|
||||
@ -127,12 +143,13 @@ impl TypeInfo {
|
||||
}
|
||||
|
||||
pub fn can_negate(&self) -> bool {
|
||||
matches!(self, TypeInfo::Integer)
|
||||
matches!(self, TypeInfo::Integer | TypeInfo::Double)
|
||||
}
|
||||
|
||||
pub fn negate_result(&self) -> TypeInfo {
|
||||
match self {
|
||||
TypeInfo::Integer => TypeInfo::Integer,
|
||||
TypeInfo::Double => TypeInfo::Double,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ pub enum Instruction {
|
||||
|
||||
Add(AddOperand, AddOperand, Location),
|
||||
Subtract(SubtractOperand, SubtractOperand, Location),
|
||||
Multiply(MultiplyOperand, MultiplyOperand, Location),
|
||||
|
||||
Pop(Option<Location>),
|
||||
|
||||
@ -54,6 +55,9 @@ impl Display for Instruction {
|
||||
Instruction::Subtract(left, right, destination) => {
|
||||
write!(f, "sub {}, {}, {}", left, right, destination)
|
||||
}
|
||||
Instruction::Multiply(left, right, destination) => {
|
||||
write!(f, "mul {}, {}, {}", left, right, destination)
|
||||
}
|
||||
Instruction::SetReturnValue(source) => {
|
||||
write!(f, "srv {}", source)
|
||||
}
|
||||
@ -186,6 +190,28 @@ impl Display for SubtractOperand {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MultiplyOperand {
|
||||
Location(Location),
|
||||
Int(i32),
|
||||
Double(f64),
|
||||
}
|
||||
|
||||
impl Display for MultiplyOperand {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
MultiplyOperand::Location(location) => {
|
||||
write!(f, "{}", location)
|
||||
}
|
||||
MultiplyOperand::Int(i) => {
|
||||
write!(f, "{}", i)
|
||||
}
|
||||
MultiplyOperand::Double(d) => {
|
||||
write!(f, "{}", d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ReturnOperand {
|
||||
Location(Location),
|
||||
Int(i32),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::instruction::{AddOperand, SubtractOperand};
|
||||
use crate::instruction::{AddOperand, MultiplyOperand, SubtractOperand};
|
||||
use crate::vm::CallFrame;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::value::Value;
|
||||
@ -43,3 +43,21 @@ pub fn subtract_operand_to_value(
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@ use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand};
|
||||
use crate::platform_function::PlatformFunction;
|
||||
use crate::vm::constant::Constant;
|
||||
use crate::vm::function::Function;
|
||||
use crate::vm::instruction_helpers::{add_operand_to_value, subtract_operand_to_value};
|
||||
use crate::vm::instruction_helpers::{
|
||||
add_operand_to_value, multiply_operand_to_value, subtract_operand_to_value,
|
||||
};
|
||||
use crate::vm::value::Value;
|
||||
use crate::vm::value_util::*;
|
||||
use std::collections::HashMap;
|
||||
@ -389,6 +391,29 @@ pub fn call<'a>(
|
||||
put_value(registers, call_stack.top_mut(), destination, result);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
Instruction::Multiply(left_operand, right_operand, destination) => {
|
||||
let left_value =
|
||||
multiply_operand_to_value(left_operand, registers, call_stack.top());
|
||||
let right_value =
|
||||
multiply_operand_to_value(right_operand, registers, call_stack.top());
|
||||
|
||||
let result = match left_value {
|
||||
Value::Int(li) => match right_value {
|
||||
Value::Int(ri) => Value::Int(li * ri),
|
||||
Value::Double(rd) => Value::Double(li as f64 * rd),
|
||||
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
|
||||
},
|
||||
Value::Double(ld) => match right_value {
|
||||
Value::Int(ri) => Value::Double(ld * ri as f64),
|
||||
Value::Double(rd) => Value::Double(ld * rd),
|
||||
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
|
||||
},
|
||||
_ => panic!("Attempt to multiply {:?} and {:?}", left_value, right_value),
|
||||
};
|
||||
|
||||
put_value(registers, call_stack.top_mut(), destination, result);
|
||||
call_stack.top_mut().increment_ip();
|
||||
}
|
||||
|
||||
/* Pop instructions */
|
||||
Instruction::Pop(maybe_location) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user