Compare commits
3 Commits
e486b212ae
...
ebca87ddb9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebca87ddb9 | ||
|
|
e35bacb583 | ||
|
|
9d09f7481b |
@ -47,14 +47,26 @@ fn main() {
|
|||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
|
||||||
let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table);
|
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||||
check_and_report_diagnostics(&files, script_file_id, &gather_names_diagnostics);
|
Ok(_) => {}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
report_and_exit(&diagnostics, script_file_id, &files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table);
|
match compilation_unit.check_name_usages(&symbol_table) {
|
||||||
check_and_report_diagnostics(&files, script_file_id, &name_usages_diagnostics);
|
Ok(_) => {}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
report_and_exit(&diagnostics, script_file_id, &files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
match compilation_unit.type_check(&symbol_table) {
|
||||||
check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics);
|
Ok(_) => {}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
report_and_exit(&diagnostics, script_file_id, &files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||||
|
|
||||||
@ -118,6 +130,15 @@ fn check_and_report_diagnostics(
|
|||||||
diagnostics: &[Diagnostic],
|
diagnostics: &[Diagnostic],
|
||||||
) {
|
) {
|
||||||
if !diagnostics.is_empty() {
|
if !diagnostics.is_empty() {
|
||||||
|
report_and_exit(diagnostics, script_file_id, files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_and_exit(
|
||||||
|
diagnostics: &[Diagnostic],
|
||||||
|
script_file_id: usize,
|
||||||
|
files: &SimpleFiles<&str, &str>,
|
||||||
|
) -> ! {
|
||||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||||
let config = term::Config::default();
|
let config = term::Config::default();
|
||||||
for diagnostic in diagnostics {
|
for diagnostic in diagnostics {
|
||||||
@ -139,5 +160,4 @@ fn check_and_report_diagnostics(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,28 +6,41 @@ use crate::source_range::SourceRange;
|
|||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
pub struct AdditiveExpression {
|
pub struct AddExpression {
|
||||||
lhs: Box<Expression>,
|
lhs: Box<Expression>,
|
||||||
rhs: Box<Expression>,
|
rhs: Box<Expression>,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
|
type_info: Option<TypeInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AdditiveExpression {
|
impl AddExpression {
|
||||||
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lhs: lhs.into(),
|
lhs: lhs.into(),
|
||||||
rhs: rhs.into(),
|
rhs: rhs.into(),
|
||||||
source_range,
|
source_range,
|
||||||
|
type_info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lhs(&self) -> &Expression {
|
||||||
|
&self.lhs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rhs(&self) -> &Expression {
|
||||||
|
&self.rhs
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn gather_declared_names(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
|
||||||
diagnostics.append(&mut self.lhs.gather_declared_names(symbol_table));
|
.iter_mut()
|
||||||
diagnostics.append(&mut self.rhs.gather_declared_names(symbol_table));
|
.map(|expression| expression.gather_declared_names(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
if diagnostics.is_empty() {
|
if diagnostics.is_empty() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -36,9 +49,12 @@ impl AdditiveExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
|
||||||
diagnostics.append(&mut self.lhs.check_name_usages(symbol_table));
|
.iter_mut()
|
||||||
diagnostics.append(&mut self.rhs.check_name_usages(symbol_table));
|
.map(|expression| expression.check_name_usages(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
if diagnostics.is_empty() {
|
if diagnostics.is_empty() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -47,12 +63,13 @@ impl AdditiveExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.lhs.type_check(symbol_table);
|
self.lhs.type_check(symbol_table)?;
|
||||||
self.rhs.type_check(symbol_table);
|
self.rhs.type_check(symbol_table)?;
|
||||||
|
|
||||||
let lhs_type_info = self.lhs.type_info();
|
let lhs_type_info = self.lhs.type_info();
|
||||||
let rhs_type_info = self.rhs.type_info();
|
let rhs_type_info = self.rhs.type_info();
|
||||||
if lhs_type_info.can_add(&rhs_type_info) {
|
if lhs_type_info.can_add(rhs_type_info) {
|
||||||
|
self.type_info = Some(lhs_type_info.add_result(rhs_type_info));
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(vec![Diagnostic::new(
|
Err(vec![Diagnostic::new(
|
||||||
@ -75,8 +92,8 @@ impl AdditiveExpression {
|
|||||||
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
|
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> TypeInfo {
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
self.type_info.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
@ -14,6 +14,7 @@ pub struct Call {
|
|||||||
callee: Box<Expression>,
|
callee: Box<Expression>,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
|
return_type_info: Option<TypeInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Call {
|
impl Call {
|
||||||
@ -22,6 +23,7 @@ impl Call {
|
|||||||
callee: callee.into(),
|
callee: callee.into(),
|
||||||
arguments,
|
arguments,
|
||||||
source_range,
|
source_range,
|
||||||
|
return_type_info: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,44 +35,74 @@ impl Call {
|
|||||||
self.arguments.iter().collect()
|
self.arguments.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
let mut diagnostics = vec![];
|
&mut self,
|
||||||
diagnostics.append(&mut self.callee.gather_declared_names(symbol_table));
|
symbol_table: &mut SymbolTable,
|
||||||
for argument in &mut self.arguments {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
diagnostics.append(&mut argument.gather_declared_names(symbol_table));
|
let mut to_gather = vec![];
|
||||||
|
to_gather.push(self.callee.as_mut());
|
||||||
|
to_gather.extend(&mut self.arguments);
|
||||||
|
|
||||||
|
let diagnostics: Vec<Diagnostic> = to_gather
|
||||||
|
.iter_mut()
|
||||||
|
.map(|expression| expression.gather_declared_names(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut to_check = vec![];
|
||||||
diagnostics.append(&mut self.callee.check_name_usages(symbol_table));
|
to_check.push(self.callee.as_mut());
|
||||||
for argument in &mut self.arguments {
|
to_check.extend(&mut self.arguments);
|
||||||
diagnostics.append(&mut argument.check_name_usages(symbol_table));
|
let diagnostics: Vec<Diagnostic> = to_check
|
||||||
|
.iter_mut()
|
||||||
|
.map(|expression| expression.check_name_usages(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
self.callee.as_mut().type_check(symbol_table)?;
|
||||||
diagnostics.append(&mut self.callee.type_check(symbol_table));
|
|
||||||
for argument in &mut self.arguments {
|
let mut diagnostics: Vec<Diagnostic> = self
|
||||||
diagnostics.append(&mut argument.type_check(symbol_table));
|
.arguments
|
||||||
}
|
.iter_mut()
|
||||||
|
.map(|argument| argument.type_check(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
// check that callee is callable
|
// check that callee is callable
|
||||||
let function_symbol = match self.callee.type_info() {
|
let function_symbol = match self.callee.type_info() {
|
||||||
TypeInfo::Function(function_symbol) => function_symbol,
|
TypeInfo::Function(function_symbol) => function_symbol,
|
||||||
_ => {
|
_ => {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
"Receiver is not callable",
|
&format!(
|
||||||
|
"Receiver of type {} is not callable.",
|
||||||
|
self.callee.type_info()
|
||||||
|
),
|
||||||
self.callee.source_range().start(),
|
self.callee.source_range().start(),
|
||||||
self.callee.source_range().end(),
|
self.callee.source_range().end(),
|
||||||
));
|
));
|
||||||
return diagnostics;
|
return Err(diagnostics);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set return type
|
||||||
|
self.return_type_info = Some(function_symbol.borrow().return_type_info().clone());
|
||||||
|
|
||||||
// check arguments length
|
// check arguments length
|
||||||
let function_symbol_ref = function_symbol.borrow();
|
let function_symbol_ref = function_symbol.borrow();
|
||||||
let parameters = function_symbol_ref.parameters();
|
let parameters = function_symbol_ref.parameters();
|
||||||
@ -87,23 +119,20 @@ impl Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !diagnostics.is_empty() {
|
if !diagnostics.is_empty() {
|
||||||
return diagnostics;
|
return Err(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check argument types
|
// check argument types
|
||||||
for i in 0..parameters.len() {
|
for i in 0..parameters.len() {
|
||||||
let parameter = ¶meters[i];
|
let parameter = ¶meters[i].borrow();
|
||||||
let argument = &self.arguments[i];
|
let argument = &self.arguments[i];
|
||||||
if !parameter
|
let parameter_type_info = parameter.type_info();
|
||||||
.borrow()
|
let argument_type_info = argument.type_info();
|
||||||
.type_info()
|
if !parameter_type_info.is_assignable_from(argument_type_info) {
|
||||||
.is_assignable_from(&argument.type_info())
|
|
||||||
{
|
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
&format!(
|
&format!(
|
||||||
"Mismatched types; expected {} but found {}",
|
"Mismatched types: expected {} but found {}",
|
||||||
parameter.borrow().type_info(),
|
parameter_type_info, argument_type_info
|
||||||
argument.type_info()
|
|
||||||
),
|
),
|
||||||
argument.source_range().start(),
|
argument.source_range().start(),
|
||||||
argument.source_range().end(),
|
argument.source_range().end(),
|
||||||
@ -111,14 +140,15 @@ impl Call {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> TypeInfo {
|
pub fn return_type_info(&self) -> &TypeInfo {
|
||||||
match self.callee.type_info() {
|
self.return_type_info.as_ref().unwrap()
|
||||||
TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_callee_symbol(&self) -> Rc<RefCell<FunctionSymbol>> {
|
fn get_callee_symbol(&self) -> Rc<RefCell<FunctionSymbol>> {
|
||||||
|
|||||||
@ -16,30 +16,57 @@ impl CompilationUnit {
|
|||||||
&self.declarations
|
&self.declarations
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
let mut diagnostics = vec![];
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
symbol_table.push_scope("compilation_unit_scope");
|
symbol_table.push_scope("compilation_unit_scope");
|
||||||
for declaration in &mut self.declarations {
|
|
||||||
diagnostics.append(&mut declaration.gather_declared_names(symbol_table));
|
let diagnostics: Vec<Diagnostic> = self
|
||||||
}
|
.declarations
|
||||||
|
.iter_mut()
|
||||||
|
.map(|declaration| declaration.gather_declared_names(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
diagnostics
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let diagnostics: Vec<Diagnostic> = self
|
||||||
for declaration in &mut self.declarations {
|
.declarations
|
||||||
diagnostics.append(&mut declaration.check_name_usages(symbol_table));
|
.iter_mut()
|
||||||
|
.map(|declaration| declaration.check_name_usages(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let diagnostics: Vec<Diagnostic> = self
|
||||||
for declaration in &mut self.declarations {
|
.declarations
|
||||||
diagnostics.append(&mut declaration.type_check(symbol_table));
|
.iter_mut()
|
||||||
|
.map(|declaration| declaration.type_check(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec<IrFunction> {
|
pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec<IrFunction> {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
use crate::ast::additive_expression::AdditiveExpression;
|
use crate::ast::add_expression::AddExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
|
use crate::ast::negative_expression::NegativeExpression;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
|
use crate::ast::subtract_expression::SubtractExpression;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_assign::IrAssign;
|
use crate::ir::ir_assign::IrAssign;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
@ -17,78 +19,88 @@ use std::cell::RefCell;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
|
Add(AddExpression),
|
||||||
|
Subtract(SubtractExpression),
|
||||||
|
Negative(NegativeExpression),
|
||||||
Call(Call),
|
Call(Call),
|
||||||
IntegerLiteral(IntegerLiteral),
|
|
||||||
String(StringLiteral),
|
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
Additive(AdditiveExpression),
|
Integer(IntegerLiteral),
|
||||||
|
String(StringLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
|
Expression::Add(add_expression) => add_expression.gather_declared_names(symbol_table),
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
subtract_expression.gather_declared_names(symbol_table)
|
||||||
|
}
|
||||||
|
Expression::Negative(negative_expression) => {
|
||||||
|
negative_expression.gather_declared_names(symbol_table)
|
||||||
|
}
|
||||||
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
||||||
Expression::Additive(additive_expression) => {
|
Expression::Integer(_) => Ok(()),
|
||||||
match additive_expression.gather_declared_names(symbol_table) {
|
Expression::String(_) => Ok(()),
|
||||||
Ok(_) => {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
Err(diagnostics) => diagnostics,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
|
Expression::Add(add_expression) => add_expression.check_name_usages(symbol_table),
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
subtract_expression.check_name_usages(symbol_table)
|
||||||
|
}
|
||||||
|
Expression::Negative(negative_expression) => {
|
||||||
|
negative_expression.check_name_usages(symbol_table)
|
||||||
|
}
|
||||||
Expression::Call(call) => call.check_name_usages(symbol_table),
|
Expression::Call(call) => call.check_name_usages(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
||||||
Expression::Additive(additive_expression) => {
|
Expression::Integer(_) => Ok(()),
|
||||||
match additive_expression.check_name_usages(symbol_table) {
|
Expression::String(_) => Ok(()),
|
||||||
Ok(_) => {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
Err(diagnostics) => diagnostics,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
|
Expression::Add(add_expression) => add_expression.type_check(symbol_table),
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
subtract_expression.type_check(symbol_table)
|
||||||
|
}
|
||||||
|
Expression::Negative(negative_expression) => {
|
||||||
|
negative_expression.type_check(symbol_table)
|
||||||
|
}
|
||||||
Expression::Call(call) => call.type_check(symbol_table),
|
Expression::Call(call) => call.type_check(symbol_table),
|
||||||
Expression::Additive(additive_expression) => {
|
Expression::Identifier(identifier) => identifier.type_check(symbol_table),
|
||||||
match additive_expression.type_check(symbol_table) {
|
Expression::Integer(_) => Ok(()),
|
||||||
Ok(_) => {
|
Expression::String(_) => Ok(()),
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
Err(diagnostics) => diagnostics,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> TypeInfo {
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
match self {
|
match self {
|
||||||
Expression::Call(call) => call.type_info(),
|
Expression::Add(add_expression) => add_expression.type_info(),
|
||||||
Expression::IntegerLiteral(_) => TypeInfo::Integer,
|
Expression::Subtract(subtract_expression) => subtract_expression.type_info(),
|
||||||
Expression::String(_) => TypeInfo::String,
|
Expression::Negative(negative_expression) => negative_expression.type_info(),
|
||||||
|
Expression::Call(call) => call.return_type_info(),
|
||||||
Expression::Identifier(identifier) => identifier.type_info(),
|
Expression::Identifier(identifier) => identifier.type_info(),
|
||||||
Expression::Additive(additive_expression) => additive_expression.type_info(),
|
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
||||||
|
Expression::String(string_literal) => string_literal.type_info(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
match self {
|
match self {
|
||||||
|
Expression::Add(additive_expression) => additive_expression.source_range(),
|
||||||
|
Expression::Subtract(subtract_expression) => subtract_expression.source_range(),
|
||||||
|
Expression::Negative(negative_expression) => negative_expression.source_range(),
|
||||||
Expression::Call(call) => call.source_range(),
|
Expression::Call(call) => call.source_range(),
|
||||||
Expression::IntegerLiteral(integer_literal) => integer_literal.source_range(),
|
|
||||||
Expression::String(string_literal) => string_literal.source_range(),
|
|
||||||
Expression::Identifier(identifier) => identifier.source_range(),
|
Expression::Identifier(identifier) => identifier.source_range(),
|
||||||
Expression::Additive(additive_expression) => additive_expression.source_range(),
|
Expression::Integer(integer_literal) => integer_literal.source_range(),
|
||||||
|
Expression::String(string_literal) => string_literal.source_range(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +112,7 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
Expression::Call(call) => {
|
Expression::Call(call) => {
|
||||||
let ir_call = call.to_ir(builder, symbol_table);
|
let ir_call = call.to_ir(builder, symbol_table);
|
||||||
if matches!(call.type_info(), TypeInfo::Void) {
|
if matches!(call.return_type_info(), TypeInfo::Void) {
|
||||||
builder
|
builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
.add_statement(IrStatement::Call(ir_call));
|
.add_statement(IrStatement::Call(ir_call));
|
||||||
@ -109,7 +121,7 @@ impl Expression {
|
|||||||
let t_var = IrVariable::new_vr(
|
let t_var = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
call.type_info(),
|
call.return_type_info(),
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(RefCell::new(t_var));
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
||||||
@ -119,7 +131,7 @@ impl Expression {
|
|||||||
Some(IrExpression::Variable(as_rc))
|
Some(IrExpression::Variable(as_rc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::IntegerLiteral(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
Some(IrExpression::Int(integer_literal.value()))
|
Some(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
@ -129,7 +141,7 @@ impl Expression {
|
|||||||
let expressible_symbol = identifier.expressible_symbol();
|
let expressible_symbol = identifier.expressible_symbol();
|
||||||
Some(expressible_symbol.ir_expression())
|
Some(expressible_symbol.ir_expression())
|
||||||
}
|
}
|
||||||
Expression::Additive(additive_expression) => {
|
Expression::Add(additive_expression) => {
|
||||||
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
||||||
let t_var = IrVariable::new_vr(
|
let t_var = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
@ -143,6 +155,10 @@ impl Expression {
|
|||||||
.add_statement(IrStatement::Assign(assign));
|
.add_statement(IrStatement::Assign(assign));
|
||||||
Some(IrExpression::Variable(as_rc))
|
Some(IrExpression::Variable(as_rc))
|
||||||
}
|
}
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
Some(subtract_expression.to_ir_expression(builder, symbol_table))
|
||||||
|
}
|
||||||
|
Expression::Negative(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,15 +20,18 @@ impl ExpressionStatement {
|
|||||||
&self.expression
|
&self.expression
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.expression.gather_declared_names(symbol_table)
|
self.expression.gather_declared_names(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.expression.check_name_usages(symbol_table)
|
self.expression.check_name_usages(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.expression.type_check(symbol_table)
|
self.expression.type_check(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,10 @@ impl ExternFunction {
|
|||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||||
@ -53,7 +56,7 @@ impl ExternFunction {
|
|||||||
self.declared_name_source_range.start(),
|
self.declared_name_source_range.start(),
|
||||||
self.declared_name_source_range.end(),
|
self.declared_name_source_range.end(),
|
||||||
));
|
));
|
||||||
diagnostics
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -79,24 +82,40 @@ impl ExternFunction {
|
|||||||
|
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
|
|
||||||
diagnostics
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.parameters
|
let diagnostics: Vec<Diagnostic> = self
|
||||||
|
.parameters
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||||
.filter_map(Result::err)
|
.filter_map(Result::err)
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect()
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.parameters
|
let diagnostics: Vec<Diagnostic> = self
|
||||||
|
.parameters
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|parameter| parameter.type_check(symbol_table))
|
.map(|parameter| parameter.type_check(symbol_table))
|
||||||
.filter_map(Result::err)
|
.filter_map(Result::err)
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect()
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,10 @@ impl Function {
|
|||||||
self.statements.iter().collect()
|
self.statements.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// insert function symbol
|
// insert function symbol
|
||||||
@ -75,7 +78,7 @@ impl Function {
|
|||||||
self.declared_name_source_range.start(),
|
self.declared_name_source_range.start(),
|
||||||
self.declared_name_source_range.end(),
|
self.declared_name_source_range.end(),
|
||||||
));
|
));
|
||||||
diagnostics
|
Err(diagnostics)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -103,14 +106,24 @@ impl Function {
|
|||||||
|
|
||||||
symbol_table.push_scope(&format!("body_scope({})", self.declared_name));
|
symbol_table.push_scope(&format!("body_scope({})", self.declared_name));
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
diagnostics.append(&mut statement.gather_declared_names(symbol_table));
|
match statement.gather_declared_names(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut statement_diagnostics) => {
|
||||||
|
diagnostics.append(&mut statement_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
symbol_table.pop_scope(); // body
|
symbol_table.pop_scope(); // body
|
||||||
symbol_table.pop_scope(); // params
|
symbol_table.pop_scope(); // params
|
||||||
diagnostics
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
@ -126,12 +139,22 @@ impl Function {
|
|||||||
|
|
||||||
// statements
|
// statements
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
diagnostics.append(&mut statement.check_name_usages(symbol_table));
|
match statement.check_name_usages(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut statement_diagnostics) => {
|
||||||
|
diagnostics.append(&mut statement_diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
diagnostics
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
@ -140,17 +163,27 @@ impl Function {
|
|||||||
.parameters
|
.parameters
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|parameter| parameter.type_check(symbol_table))
|
.map(|parameter| parameter.type_check(symbol_table))
|
||||||
.filter_map(|result| result.err())
|
.filter_map(Result::err)
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
for statement in &mut self.statements {
|
diagnostics.append(
|
||||||
diagnostics.append(&mut statement.type_check(symbol_table));
|
&mut self
|
||||||
}
|
.statements
|
||||||
|
.iter_mut()
|
||||||
|
.map(|statement| statement.type_check(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
diagnostics
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> IrFunction {
|
pub fn to_ir(&self, symbol_table: &SymbolTable) -> IrFunction {
|
||||||
@ -172,12 +205,8 @@ impl Function {
|
|||||||
|
|
||||||
let entry_block_id = builder.new_block();
|
let entry_block_id = builder.new_block();
|
||||||
|
|
||||||
let return_type_info = self
|
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
||||||
.function_symbol
|
let return_type_info = function_symbol.return_type_info();
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.borrow()
|
|
||||||
.return_type();
|
|
||||||
|
|
||||||
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub struct Identifier {
|
|||||||
name: String,
|
name: String,
|
||||||
scope_id: Option<usize>,
|
scope_id: Option<usize>,
|
||||||
expressible_symbol: Option<ExpressibleSymbol>,
|
expressible_symbol: Option<ExpressibleSymbol>,
|
||||||
|
type_info: Option<TypeInfo>,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ impl Identifier {
|
|||||||
name: name.into(),
|
name: name.into(),
|
||||||
scope_id: None,
|
scope_id: None,
|
||||||
expressible_symbol: None,
|
expressible_symbol: None,
|
||||||
|
type_info: None,
|
||||||
source_range,
|
source_range,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,41 +27,38 @@ impl Identifier {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.scope_id = Some(symbol_table.current_scope_id());
|
self.scope_id = Some(symbol_table.current_scope_id());
|
||||||
vec![]
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let maybe_expressible_symbol =
|
let maybe_expressible_symbol =
|
||||||
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
|
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
|
||||||
match maybe_expressible_symbol {
|
match maybe_expressible_symbol {
|
||||||
None => {
|
None => Err(vec![Diagnostic::new(
|
||||||
vec![Diagnostic::new(
|
|
||||||
&format!("Unable to resolve symbol {}", self.name),
|
&format!("Unable to resolve symbol {}", self.name),
|
||||||
self.source_range.start(),
|
self.source_range.start(),
|
||||||
self.source_range.end(),
|
self.source_range.end(),
|
||||||
)]
|
)]),
|
||||||
}
|
|
||||||
Some(expressible_symbol) => {
|
Some(expressible_symbol) => {
|
||||||
self.expressible_symbol = Some(expressible_symbol);
|
self.expressible_symbol = Some(expressible_symbol);
|
||||||
vec![]
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> TypeInfo {
|
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self.expressible_symbol.as_ref().unwrap() {
|
let type_info = self.expressible_symbol.as_ref().unwrap().type_info();
|
||||||
ExpressibleSymbol::Function(function_symbol) => {
|
self.type_info = Some(type_info);
|
||||||
TypeInfo::Function(function_symbol.clone())
|
Ok(())
|
||||||
}
|
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
|
||||||
parameter_symbol.borrow().type_info().clone()
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
|
||||||
variable_symbol.borrow().type_info().clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
self.type_info.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expressible_symbol(&self) -> &ExpressibleSymbol {
|
pub fn expressible_symbol(&self) -> &ExpressibleSymbol {
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
pub struct IntegerLiteral {
|
pub struct IntegerLiteral {
|
||||||
value: i32,
|
value: i32,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
|
type_info: &'static TypeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntegerLiteral {
|
impl IntegerLiteral {
|
||||||
pub fn new(value: i32, source_range: SourceRange) -> Self {
|
pub fn new(value: i32, source_range: SourceRange) -> Self {
|
||||||
|
const TYPE_INFO: TypeInfo = TypeInfo::Integer;
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
source_range,
|
source_range,
|
||||||
|
type_info: &TYPE_INFO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,6 +21,10 @@ impl IntegerLiteral {
|
|||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
&self.type_info
|
||||||
|
}
|
||||||
|
|
||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
&self.source_range
|
&self.source_range
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,9 +45,19 @@ impl LetStatement {
|
|||||||
&mut self.initializer
|
&mut self.initializer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
self.initializer_mut().gather_declared_names(symbol_table);
|
|
||||||
|
match self.initializer_mut().gather_declared_names(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut initializer_diagnostics) => {
|
||||||
|
diagnostics.append(&mut initializer_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let insert_result =
|
let insert_result =
|
||||||
symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name()));
|
symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name()));
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
if let Err(symbol_insert_error) = insert_result {
|
||||||
@ -64,32 +74,35 @@ impl LetStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.scope_id = Some(symbol_table.current_scope_id());
|
self.scope_id = Some(symbol_table.current_scope_id());
|
||||||
diagnostics
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.initializer.check_name_usages(symbol_table)
|
self.initializer.check_name_usages(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let initializer_diagnostics = self.initializer.type_check(symbol_table);
|
self.initializer.type_check(symbol_table)?;
|
||||||
if !initializer_diagnostics.is_empty() {
|
|
||||||
return initializer_diagnostics;
|
|
||||||
}
|
|
||||||
let initializer_type_info = self.initializer.type_info();
|
let initializer_type_info = self.initializer.type_info();
|
||||||
let variable_symbol =
|
let variable_symbol =
|
||||||
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
||||||
variable_symbol
|
variable_symbol
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_type_info(initializer_type_info);
|
.set_type_info(initializer_type_info.clone());
|
||||||
vec![]
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
||||||
let init_operation = match self.initializer() {
|
let init_operation = match self.initializer() {
|
||||||
Expression::Call(call) => IrOperation::Call(call.to_ir(builder, symbol_table)),
|
Expression::Call(call) => IrOperation::Call(call.to_ir(builder, symbol_table)),
|
||||||
Expression::IntegerLiteral(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
@ -98,9 +111,13 @@ impl LetStatement {
|
|||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
IrOperation::Load(identifier.expressible_symbol().ir_expression())
|
IrOperation::Load(identifier.expressible_symbol().ir_expression())
|
||||||
}
|
}
|
||||||
Expression::Additive(additive_expression) => {
|
Expression::Add(additive_expression) => {
|
||||||
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
||||||
}
|
}
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
IrOperation::Subtract(subtract_expression.to_ir_subtract(builder, symbol_table))
|
||||||
|
}
|
||||||
|
Expression::Negative(_) => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let destination_symbol =
|
let destination_symbol =
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
pub mod additive_expression;
|
pub mod add_expression;
|
||||||
pub mod call;
|
pub mod call;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
@ -11,7 +11,9 @@ pub mod integer_literal;
|
|||||||
pub mod ir_builder;
|
pub mod ir_builder;
|
||||||
pub mod let_statement;
|
pub mod let_statement;
|
||||||
pub mod module_level_declaration;
|
pub mod module_level_declaration;
|
||||||
|
pub mod negative_expression;
|
||||||
pub mod parameter;
|
pub mod parameter;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod string_literal;
|
pub mod string_literal;
|
||||||
|
pub mod subtract_expression;
|
||||||
pub mod type_use;
|
pub mod type_use;
|
||||||
|
|||||||
@ -9,7 +9,10 @@ pub enum ModuleLevelDeclaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleLevelDeclaration {
|
impl ModuleLevelDeclaration {
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
ModuleLevelDeclaration::Function(function) => {
|
ModuleLevelDeclaration::Function(function) => {
|
||||||
function.gather_declared_names(symbol_table)
|
function.gather_declared_names(symbol_table)
|
||||||
@ -20,7 +23,7 @@ impl ModuleLevelDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
ModuleLevelDeclaration::Function(function) => function.check_name_usages(symbol_table),
|
ModuleLevelDeclaration::Function(function) => function.check_name_usages(symbol_table),
|
||||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||||
@ -29,7 +32,7 @@ impl ModuleLevelDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
ModuleLevelDeclaration::Function(function) => function.type_check(symbol_table),
|
ModuleLevelDeclaration::Function(function) => function.type_check(symbol_table),
|
||||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||||
|
|||||||
64
dmc-lib/src/ast/negative_expression.rs
Normal file
64
dmc-lib/src/ast/negative_expression.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
|
pub struct NegativeExpression {
|
||||||
|
operand: Box<Expression>,
|
||||||
|
source_range: SourceRange,
|
||||||
|
type_info: Option<TypeInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NegativeExpression {
|
||||||
|
pub fn new(operand: Expression, source_range: SourceRange) -> Self {
|
||||||
|
Self {
|
||||||
|
operand: operand.into(),
|
||||||
|
source_range,
|
||||||
|
type_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
|
&self.source_range
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand(&self) -> &Expression {
|
||||||
|
&self.operand
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand_mut(&mut self) -> &mut Expression {
|
||||||
|
&mut self.operand
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.operand.gather_declared_names(symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.operand.check_name_usages(symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.operand.type_check(symbol_table)?;
|
||||||
|
|
||||||
|
let type_info = self.operand.type_info();
|
||||||
|
if type_info.can_negate() {
|
||||||
|
self.type_info = Some(type_info.negate_result());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(vec![Diagnostic::new(
|
||||||
|
&format!("Cannot negate {}", type_info),
|
||||||
|
self.source_range.start(),
|
||||||
|
self.source_range.end(),
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
self.type_info.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,10 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.gather_declared_names(symbol_table),
|
Statement::Let(let_statement) => let_statement.gather_declared_names(symbol_table),
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
@ -19,7 +22,7 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.check_name_usages(symbol_table),
|
Statement::Let(let_statement) => let_statement.check_name_usages(symbol_table),
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
@ -28,7 +31,7 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.type_check(symbol_table),
|
Statement::Let(let_statement) => let_statement.type_check(symbol_table),
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
pub struct StringLiteral {
|
pub struct StringLiteral {
|
||||||
content: String,
|
content: String,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
|
type_info: &'static TypeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StringLiteral {
|
impl StringLiteral {
|
||||||
pub fn new(content: &str, source_range: SourceRange) -> Self {
|
pub fn new(content: &str, source_range: SourceRange) -> Self {
|
||||||
|
const TYPE_INFO: TypeInfo = TypeInfo::Integer;
|
||||||
Self {
|
Self {
|
||||||
content: content.into(),
|
content: content.into(),
|
||||||
source_range,
|
source_range,
|
||||||
|
type_info: &TYPE_INFO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,6 +21,10 @@ impl StringLiteral {
|
|||||||
&self.content
|
&self.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
&self.type_info
|
||||||
|
}
|
||||||
|
|
||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
&self.source_range
|
&self.source_range
|
||||||
}
|
}
|
||||||
|
|||||||
135
dmc-lib/src/ast/subtract_expression.rs
Normal file
135
dmc-lib/src/ast/subtract_expression.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
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_operation::IrOperation;
|
||||||
|
use crate::ir::ir_statement::IrStatement;
|
||||||
|
use crate::ir::ir_subtract::IrSubtract;
|
||||||
|
use crate::ir::ir_variable::IrVariable;
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct SubtractExpression {
|
||||||
|
lhs: Box<Expression>,
|
||||||
|
rhs: Box<Expression>,
|
||||||
|
source_range: SourceRange,
|
||||||
|
type_info: Option<TypeInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubtractExpression {
|
||||||
|
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
||||||
|
Self {
|
||||||
|
lhs: lhs.into(),
|
||||||
|
rhs: rhs.into(),
|
||||||
|
source_range,
|
||||||
|
type_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lhs(&self) -> &Expression {
|
||||||
|
&self.lhs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rhs(&self) -> &Expression {
|
||||||
|
&self.rhs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let diagnostics = [&mut self.lhs, &mut self.rhs]
|
||||||
|
.iter_mut()
|
||||||
|
.map(|expression| expression.gather_declared_names(symbol_table))
|
||||||
|
.filter_map(|result| result.err())
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<Diagnostic>>();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let diagnostics: Vec<Diagnostic> = [&mut self.lhs, &mut self.rhs]
|
||||||
|
.iter_mut()
|
||||||
|
.map(|expression| expression.check_name_usages(symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.lhs.type_check(symbol_table)?;
|
||||||
|
self.rhs.type_check(symbol_table)?;
|
||||||
|
|
||||||
|
let lhs_type_info = self.lhs.type_info();
|
||||||
|
let rhs_type_info = self.rhs.type_info();
|
||||||
|
if lhs_type_info.can_subtract(rhs_type_info) {
|
||||||
|
self.type_info = Some(lhs_type_info.add_result(rhs_type_info));
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(vec![Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Incompatible types: cannot subtract {} from {}",
|
||||||
|
rhs_type_info, lhs_type_info
|
||||||
|
), // n.b. order
|
||||||
|
self.lhs.source_range().start(),
|
||||||
|
self.lhs.source_range().end(),
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
|
self.type_info.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
|
&self.source_range
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ir_subtract(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> IrSubtract {
|
||||||
|
let lhs = self
|
||||||
|
.lhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
|
.expect("Attempt to subtract non-expression");
|
||||||
|
let rhs = self
|
||||||
|
.rhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
|
.expect("Attempt to subtract non-expression");
|
||||||
|
IrSubtract::new(lhs, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ir_expression(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> IrExpression {
|
||||||
|
let ir_subtract = self.to_ir_subtract(builder, symbol_table);
|
||||||
|
let t_var = IrVariable::new_vr(
|
||||||
|
builder.new_t_var().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
self.type_info(),
|
||||||
|
);
|
||||||
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Subtract(ir_subtract));
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(assign));
|
||||||
|
IrExpression::Variable(as_rc)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -97,6 +97,10 @@ impl Assemble for IrAssign {
|
|||||||
let (left, right) = ir_add.operand_pair(constants_table);
|
let (left, right) = ir_add.operand_pair(constants_table);
|
||||||
builder.push(Instruction::Add(left, right, destination));
|
builder.push(Instruction::Add(left, right, destination));
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
let (left, right) = ir_subtract.operand_pair();
|
||||||
|
builder.push(Instruction::Subtract(left, right, destination));
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.assemble(builder, constants_table);
|
ir_call.assemble(builder, constants_table);
|
||||||
builder.push(Instruction::Pop(Some(destination)));
|
builder.push(Instruction::Pop(Some(destination)));
|
||||||
|
|||||||
@ -5,7 +5,9 @@ use crate::ir::ir_variable::{
|
|||||||
};
|
};
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand};
|
use dvm_lib::instruction::{
|
||||||
|
AddOperand, Location, MoveOperand, PushOperand, ReturnOperand, SubtractOperand,
|
||||||
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -105,6 +107,40 @@ impl IrExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subtract_operand(&self) -> SubtractOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||||
|
TypeInfo::Integer => SubtractOperand::Location(Location::StackFrameOffset(
|
||||||
|
ir_parameter.stack_offset(),
|
||||||
|
)),
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to subtract with non-integer type (found {})",
|
||||||
|
ir_parameter.type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
||||||
|
TypeInfo::Integer => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||||
|
SubtractOperand::Location(Location::Register(
|
||||||
|
vr_variable.assigned_register(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => SubtractOperand::Location(
|
||||||
|
Location::StackFrameOffset(stack_variable.offset()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to subtract with non-integer type (found {})",
|
||||||
|
ir_variable.borrow().type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => SubtractOperand::Int(*i),
|
||||||
|
IrExpression::String(_) => {
|
||||||
|
panic!("Attempt to subtract with a string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
|
||||||
match self {
|
match self {
|
||||||
IrExpression::Parameter(ir_parameter) => {
|
IrExpression::Parameter(ir_parameter) => {
|
||||||
|
|||||||
@ -23,13 +23,13 @@ impl IrFunction {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||||
parameters: &[Rc<IrParameter>],
|
parameters: &[Rc<IrParameter>],
|
||||||
return_type_info: TypeInfo,
|
return_type_info: &TypeInfo,
|
||||||
entry: Rc<RefCell<IrBlock>>,
|
entry: Rc<RefCell<IrBlock>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_symbol,
|
function_symbol,
|
||||||
parameters: parameters.to_vec(),
|
parameters: parameters.to_vec(),
|
||||||
return_type_info,
|
return_type_info: return_type_info.clone(),
|
||||||
entry,
|
entry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::ir::ir_add::IrAdd;
|
use crate::ir::ir_add::IrAdd;
|
||||||
use crate::ir::ir_call::IrCall;
|
use crate::ir::ir_call::IrCall;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_subtract::IrSubtract;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
@ -9,6 +10,7 @@ use std::fmt::{Display, Formatter};
|
|||||||
pub enum IrOperation {
|
pub enum IrOperation {
|
||||||
Load(IrExpression),
|
Load(IrExpression),
|
||||||
Add(IrAdd),
|
Add(IrAdd),
|
||||||
|
Subtract(IrSubtract),
|
||||||
Call(IrCall),
|
Call(IrCall),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ impl Display for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
write!(f, "{}", ir_add)
|
write!(f, "{}", ir_add)
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
write!(f, "{}", ir_subtract)
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
write!(f, "{}", ir_call)
|
write!(f, "{}", ir_call)
|
||||||
}
|
}
|
||||||
@ -33,6 +38,7 @@ impl VrUser for IrOperation {
|
|||||||
match self {
|
match self {
|
||||||
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
|
||||||
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
|
||||||
|
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(),
|
||||||
IrOperation::Call(ir_call) => ir_call.vr_definitions(),
|
IrOperation::Call(ir_call) => ir_call.vr_definitions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,6 +47,7 @@ impl VrUser for IrOperation {
|
|||||||
match self {
|
match self {
|
||||||
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
|
||||||
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
IrOperation::Add(ir_add) => ir_add.vr_uses(),
|
||||||
|
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
|
||||||
IrOperation::Call(ir_call) => ir_call.vr_uses(),
|
IrOperation::Call(ir_call) => ir_call.vr_uses(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,6 +60,9 @@ impl VrUser for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
ir_add.propagate_spills(spills);
|
ir_add.propagate_spills(spills);
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
ir_subtract.propagate_spills(spills);
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.propagate_spills(spills);
|
ir_call.propagate_spills(spills);
|
||||||
}
|
}
|
||||||
@ -70,6 +80,9 @@ impl VrUser for IrOperation {
|
|||||||
IrOperation::Add(ir_add) => {
|
IrOperation::Add(ir_add) => {
|
||||||
ir_add.propagate_register_assignments(assignments);
|
ir_add.propagate_register_assignments(assignments);
|
||||||
}
|
}
|
||||||
|
IrOperation::Subtract(ir_subtract) => {
|
||||||
|
ir_subtract.propagate_register_assignments(assignments);
|
||||||
|
}
|
||||||
IrOperation::Call(ir_call) => {
|
IrOperation::Call(ir_call) => {
|
||||||
ir_call.propagate_register_assignments(assignments);
|
ir_call.propagate_register_assignments(assignments);
|
||||||
}
|
}
|
||||||
|
|||||||
63
dmc-lib/src/ir/ir_subtract.rs
Normal file
63
dmc-lib/src/ir/ir_subtract.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
|
use crate::ir::register_allocation::{OffsetCounter, VrUser};
|
||||||
|
use dvm_lib::instruction::SubtractOperand;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
pub struct IrSubtract {
|
||||||
|
left: Box<IrExpression>,
|
||||||
|
right: Box<IrExpression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrSubtract {
|
||||||
|
pub fn new(left: IrExpression, right: IrExpression) -> Self {
|
||||||
|
Self {
|
||||||
|
left: left.into(),
|
||||||
|
right: right.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand_pair(&self) -> (SubtractOperand, SubtractOperand) {
|
||||||
|
(self.left.subtract_operand(), self.right.subtract_operand())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VrUser for IrSubtract {
|
||||||
|
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||||
|
[&self.left, &self.right]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|expression| expression.vr_definitions())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
|
||||||
|
[&self.left, &self.right]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|expression| expression.vr_uses())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
|
||||||
|
self.left.propagate_spills(spills);
|
||||||
|
self.right.propagate_spills(spills);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_register_assignments(
|
||||||
|
&mut self,
|
||||||
|
assignments: &HashMap<IrVrVariableDescriptor, usize>,
|
||||||
|
) {
|
||||||
|
self.left.propagate_register_assignments(assignments);
|
||||||
|
self.right.propagate_register_assignments(assignments);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_stack_offsets(&mut self, _counter: &mut OffsetCounter) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for IrSubtract {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{} - {}", self.left, self.right)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,19 +9,19 @@ pub struct IrVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IrVariable {
|
impl IrVariable {
|
||||||
pub fn new_vr(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
|
pub fn new_vr(name: Rc<str>, block_id: usize, type_info: &TypeInfo) -> Self {
|
||||||
Self {
|
Self {
|
||||||
descriptor: IrVariableDescriptor::VirtualRegister(IrVrVariableDescriptor::new(
|
descriptor: IrVariableDescriptor::VirtualRegister(IrVrVariableDescriptor::new(
|
||||||
name, block_id,
|
name, block_id,
|
||||||
)),
|
)),
|
||||||
type_info,
|
type_info: type_info.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_stack(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
|
pub fn new_stack(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
|
||||||
Self {
|
Self {
|
||||||
descriptor: IrVariableDescriptor::Stack(IrStackVariableDescriptor::new(name, block_id)),
|
descriptor: IrVariableDescriptor::Stack(IrStackVariableDescriptor::new(name, block_id)),
|
||||||
type_info,
|
type_info: type_info.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,5 +9,6 @@ pub mod ir_operation;
|
|||||||
pub mod ir_parameter;
|
pub mod ir_parameter;
|
||||||
pub mod ir_return;
|
pub mod ir_return;
|
||||||
pub mod ir_statement;
|
pub mod ir_statement;
|
||||||
|
pub mod ir_subtract;
|
||||||
pub mod ir_variable;
|
pub mod ir_variable;
|
||||||
mod register_allocation;
|
mod register_allocation;
|
||||||
|
|||||||
@ -36,6 +36,8 @@ impl<'a> Lexer<'a> {
|
|||||||
|
|
||||||
let token = if chunk.starts_with("->") {
|
let token = if chunk.starts_with("->") {
|
||||||
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
|
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
|
||||||
|
} else if chunk.starts_with("-") {
|
||||||
|
Token::new(self.position, self.position + 1, TokenKind::Minus)
|
||||||
} else if chunk.starts_with("(") {
|
} else if chunk.starts_with("(") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
||||||
} else if chunk.starts_with(")") {
|
} else if chunk.starts_with(")") {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::ast::additive_expression::AdditiveExpression;
|
use crate::ast::add_expression::AddExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
@ -9,9 +9,11 @@ use crate::ast::identifier::Identifier;
|
|||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||||
|
use crate::ast::negative_expression::NegativeExpression;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
|
use crate::ast::subtract_expression::SubtractExpression;
|
||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::lexer::Lexer;
|
use crate::lexer::Lexer;
|
||||||
@ -24,6 +26,12 @@ pub fn parse_compilation_unit(input: &str) -> Result<CompilationUnit, Vec<Diagno
|
|||||||
parser.compilation_unit()
|
parser.compilation_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_expression(input: &str) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
|
let mut parser = Parser::new(input);
|
||||||
|
parser.advance(); // get started
|
||||||
|
parser.expression()
|
||||||
|
}
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
lexer: Lexer<'a>,
|
lexer: Lexer<'a>,
|
||||||
@ -391,17 +399,24 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let mut result = self.suffix_expression()?;
|
let mut result = self.prefix_expression()?;
|
||||||
while self.current.is_some() {
|
while self.current.is_some() {
|
||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Plus => {
|
TokenKind::Plus => {
|
||||||
self.advance(); // plus
|
self.advance(); // plus
|
||||||
let rhs = self.suffix_expression()?;
|
let rhs = self.prefix_expression()?;
|
||||||
|
let source_range =
|
||||||
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
|
result = Expression::Add(AddExpression::new(result, rhs, source_range));
|
||||||
|
}
|
||||||
|
TokenKind::Minus => {
|
||||||
|
self.advance(); // minus
|
||||||
|
let rhs = self.prefix_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
result =
|
result =
|
||||||
Expression::Additive(AdditiveExpression::new(result, rhs, source_range));
|
Expression::Subtract(SubtractExpression::new(result, rhs, source_range));
|
||||||
}
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
@ -409,6 +424,37 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prefix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
|
// first, collect all consecutive operators
|
||||||
|
let mut operator_tokens = vec![];
|
||||||
|
while self.current.is_some() {
|
||||||
|
let current = self.get_current();
|
||||||
|
match current.kind() {
|
||||||
|
TokenKind::Minus => {
|
||||||
|
operator_tokens.push(current.clone()); // unfortunately necessary
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now go in reverse and build up expressions
|
||||||
|
// the parser is currently just after the prefix operators, so we need a suffix expression
|
||||||
|
// as a base
|
||||||
|
let mut result = self.suffix_expression()?;
|
||||||
|
while let Some(operator_token) = operator_tokens.pop() {
|
||||||
|
let source_range =
|
||||||
|
SourceRange::new(operator_token.start(), result.source_range().end());
|
||||||
|
match operator_token.kind() {
|
||||||
|
TokenKind::Minus => {
|
||||||
|
result = Expression::Negative(NegativeExpression::new(result, source_range));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
fn suffix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn suffix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let mut result = self.expression_base()?;
|
let mut result = self.expression_base()?;
|
||||||
while self.current.is_some() {
|
while self.current.is_some() {
|
||||||
@ -430,7 +476,7 @@ impl<'a> Parser<'a> {
|
|||||||
let raw = self.token_text(¤t);
|
let raw = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance();
|
||||||
Ok(Expression::IntegerLiteral(IntegerLiteral::new(
|
Ok(Expression::Integer(IntegerLiteral::new(
|
||||||
i32::from_str(raw).unwrap(),
|
i32::from_str(raw).unwrap(),
|
||||||
source_range,
|
source_range,
|
||||||
)))
|
)))
|
||||||
@ -453,7 +499,7 @@ impl<'a> Parser<'a> {
|
|||||||
source_range,
|
source_range,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!("Unreachable token type found: {:?}", current.kind()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,24 +585,90 @@ mod smoke_tests {
|
|||||||
fn add_two_numbers() {
|
fn add_two_numbers() {
|
||||||
smoke_test("fn main() 1 + 2 end");
|
smoke_test("fn main() 1 + 2 end");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn negative_return() {
|
||||||
|
smoke_test("fn main() -> Int -1 end");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn negative_left_add() {
|
||||||
|
smoke_test("fn main() -> Int -1 + 1 end");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn negative_right_add() {
|
||||||
|
smoke_test("fn main() -> Int 1 + -1 end");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_negatives() {
|
||||||
|
smoke_test("fn main() -> Int -1 + -1 end");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn minus_positive_number() {
|
||||||
|
smoke_test("fn main() -> Int 1 - 1 end");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn minus_negative_number() {
|
||||||
|
smoke_test("fn main() -> Int 1 - -1 end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod concrete_tests {
|
mod concrete_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
fn report_diagnostics(diagnostics: &[Diagnostic]) -> ! {
|
||||||
fn parses_extern_fn() {
|
|
||||||
let parse_result = parse_compilation_unit("extern fn println() -> Void");
|
|
||||||
let compilation_unit = match parse_result {
|
|
||||||
Ok(compilation_unit) => compilation_unit,
|
|
||||||
Err(diagnostics) => {
|
|
||||||
for diagnostic in diagnostics {
|
for diagnostic in diagnostics {
|
||||||
eprintln!("{:?}", diagnostic);
|
eprintln!("{:?}", diagnostic);
|
||||||
}
|
}
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
fn assert_compilation_unit(input: &str) -> CompilationUnit {
|
||||||
|
let parse_result = parse_compilation_unit(input);
|
||||||
|
match parse_result {
|
||||||
|
Ok(compilation_unit) => compilation_unit,
|
||||||
|
Err(diagnostics) => {
|
||||||
|
report_diagnostics(&diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_expression(input: &str) -> Expression {
|
||||||
|
let parse_result = parse_expression(input);
|
||||||
|
match parse_result {
|
||||||
|
Ok(expression) => expression,
|
||||||
|
Err(diagnostics) => {
|
||||||
|
report_diagnostics(&diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_function_in<'a>(
|
||||||
|
compilation_unit: &'a CompilationUnit,
|
||||||
|
function_name: &str,
|
||||||
|
) -> &'a Function {
|
||||||
|
let declarations = compilation_unit.declarations();
|
||||||
|
for declaration in declarations {
|
||||||
|
match declaration {
|
||||||
|
ModuleLevelDeclaration::Function(function) => {
|
||||||
|
if function.declared_name() == function_name {
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Function {} not found", function_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_extern_fn() {
|
||||||
|
let compilation_unit = assert_compilation_unit("extern fn println() -> Void");
|
||||||
let declarations = compilation_unit.declarations();
|
let declarations = compilation_unit.declarations();
|
||||||
assert_eq!(declarations.len(), 1);
|
assert_eq!(declarations.len(), 1);
|
||||||
let extern_function = match &declarations[0] {
|
let extern_function = match &declarations[0] {
|
||||||
@ -568,23 +680,8 @@ mod concrete_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello_world() {
|
fn hello_world() {
|
||||||
let parse_result = parse_compilation_unit("fn main() println(\"Hello, World!\") end");
|
let compilation_unit = assert_compilation_unit("fn main() println(\"Hello, World!\") end");
|
||||||
let compilation_unit = match parse_result {
|
let function = assert_function_in(&compilation_unit, "main");
|
||||||
Ok(compilation_unit) => compilation_unit,
|
|
||||||
Err(diagnostics) => {
|
|
||||||
for diagnostic in &diagnostics {
|
|
||||||
eprintln!("{:?}", diagnostic)
|
|
||||||
}
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let declarations = compilation_unit.declarations();
|
|
||||||
assert_eq!(declarations.len(), 1);
|
|
||||||
let function = match &declarations[0] {
|
|
||||||
ModuleLevelDeclaration::Function(function) => function,
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
assert_eq!(function.declared_name(), "main");
|
|
||||||
let statements = function.statements();
|
let statements = function.statements();
|
||||||
assert_eq!(statements.len(), 1);
|
assert_eq!(statements.len(), 1);
|
||||||
if let Statement::Expression(expression_statement) = statements[0] {
|
if let Statement::Expression(expression_statement) = statements[0] {
|
||||||
@ -612,6 +709,69 @@ mod concrete_tests {
|
|||||||
panic!("Expected expression");
|
panic!("Expected expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn negative_expression() {
|
||||||
|
let expression = assert_expression("-1");
|
||||||
|
match expression {
|
||||||
|
Expression::Negative(negative_expression) => match negative_expression.operand() {
|
||||||
|
Expression::Integer(integer_literal) => {
|
||||||
|
assert_eq!(integer_literal.value(), 1);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected integer literal"),
|
||||||
|
},
|
||||||
|
_ => panic!("Expected negative expression"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_negative() {
|
||||||
|
let expression = assert_expression("1 + -1");
|
||||||
|
match expression {
|
||||||
|
Expression::Add(add_expression) => {
|
||||||
|
match add_expression.lhs() {
|
||||||
|
Expression::Integer(integer_literal) => {
|
||||||
|
assert_eq!(integer_literal.value(), 1);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected integer literal"),
|
||||||
|
}
|
||||||
|
match add_expression.rhs() {
|
||||||
|
Expression::Negative(negative_expression) => {
|
||||||
|
match negative_expression.operand() {
|
||||||
|
Expression::Integer(integer_literal) => {
|
||||||
|
assert_eq!(integer_literal.value(), 1);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected integer literal"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected negative expression"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected additive expression"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_subtract() {
|
||||||
|
let expression = assert_expression("1 - 1");
|
||||||
|
match expression {
|
||||||
|
Expression::Subtract(subtract_expression) => {
|
||||||
|
match subtract_expression.lhs() {
|
||||||
|
Expression::Integer(integer_literal) => {
|
||||||
|
assert_eq!(integer_literal.value(), 1);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected integer literal"),
|
||||||
|
}
|
||||||
|
match subtract_expression.rhs() {
|
||||||
|
Expression::Integer(integer_literal) => {
|
||||||
|
assert_eq!(integer_literal.value(), 1);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected integer literal"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Expected subtract expression"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -38,8 +38,8 @@ impl FunctionSymbol {
|
|||||||
self.parameters.as_ref().unwrap()
|
self.parameters.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type(&self) -> TypeInfo {
|
pub fn return_type_info(&self) -> &TypeInfo {
|
||||||
self.return_type.clone()
|
&self.return_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_platform(&self) -> bool {
|
pub fn is_platform(&self) -> bool {
|
||||||
@ -134,6 +134,20 @@ pub enum ExpressibleSymbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExpressibleSymbol {
|
impl ExpressibleSymbol {
|
||||||
|
pub fn type_info(&self) -> TypeInfo {
|
||||||
|
match self {
|
||||||
|
ExpressibleSymbol::Function(function_symbol) => {
|
||||||
|
TypeInfo::Function(function_symbol.clone()) // n.b. not the return type!
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||||
|
parameter_symbol.borrow().type_info().clone()
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||||
|
variable_symbol.borrow().type_info().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ir_expression(&self) -> IrExpression {
|
pub fn ir_expression(&self) -> IrExpression {
|
||||||
match self {
|
match self {
|
||||||
ExpressibleSymbol::Function(_) => {
|
ExpressibleSymbol::Function(_) => {
|
||||||
|
|||||||
@ -40,4 +40,5 @@ pub enum TokenKind {
|
|||||||
Colon,
|
Colon,
|
||||||
RightArrow,
|
RightArrow,
|
||||||
Plus,
|
Plus,
|
||||||
|
Minus,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,11 +68,36 @@ impl TypeInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn additive_result(&self, _rhs: &Self) -> TypeInfo {
|
pub fn add_result(&self, _rhs: &Self) -> TypeInfo {
|
||||||
match self {
|
match self {
|
||||||
TypeInfo::Integer => TypeInfo::Integer,
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
TypeInfo::String => TypeInfo::String,
|
TypeInfo::String => TypeInfo::String,
|
||||||
_ => panic!("Adding things other than integers and strings not yet supported"),
|
_ => panic!("Adding things other than integers and strings not yet supported"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_subtract(&self, rhs: &Self) -> bool {
|
||||||
|
matches!(self, TypeInfo::Integer) && matches!(rhs, TypeInfo::Integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtract_result(&self, rhs: &Self) -> TypeInfo {
|
||||||
|
match self {
|
||||||
|
TypeInfo::Integer => match rhs {
|
||||||
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
|
_ => panic!(),
|
||||||
|
},
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn can_negate(&self) -> bool {
|
||||||
|
matches!(self, TypeInfo::Integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negate_result(&self) -> TypeInfo {
|
||||||
|
match self {
|
||||||
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub enum Instruction {
|
|||||||
InvokePlatformStatic(FunctionName, ArgCount),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
Add(AddOperand, AddOperand, Location),
|
Add(AddOperand, AddOperand, Location),
|
||||||
|
Subtract(SubtractOperand, SubtractOperand, Location),
|
||||||
|
|
||||||
Pop(Option<Location>),
|
Pop(Option<Location>),
|
||||||
|
|
||||||
@ -50,6 +51,9 @@ impl Display for Instruction {
|
|||||||
Instruction::Add(left, right, destination) => {
|
Instruction::Add(left, right, destination) => {
|
||||||
write!(f, "add {}, {}, {}", left, right, destination)
|
write!(f, "add {}, {}, {}", left, right, destination)
|
||||||
}
|
}
|
||||||
|
Instruction::Subtract(left, right, destination) => {
|
||||||
|
write!(f, "sub {}, {}, {}", left, right, destination)
|
||||||
|
}
|
||||||
Instruction::SetReturnValue(source) => {
|
Instruction::SetReturnValue(source) => {
|
||||||
write!(f, "srv {}", source)
|
write!(f, "srv {}", source)
|
||||||
}
|
}
|
||||||
@ -148,6 +152,24 @@ impl Display for AddOperand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SubtractOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SubtractOperand {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SubtractOperand::Location(location) => {
|
||||||
|
write!(f, "{}", location)
|
||||||
|
}
|
||||||
|
SubtractOperand::Int(i) => {
|
||||||
|
write!(f, "{}", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ReturnOperand {
|
pub enum ReturnOperand {
|
||||||
Location(Location),
|
Location(Location),
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
|||||||
21
dvm-lib/src/vm/instruction_helpers.rs
Normal file
21
dvm-lib/src/vm/instruction_helpers.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use crate::instruction::SubtractOperand;
|
||||||
|
use crate::vm::CallFrame;
|
||||||
|
use crate::vm::value::Value;
|
||||||
|
use crate::vm::value_util::load_value;
|
||||||
|
|
||||||
|
pub fn subtract_operand_to_value(
|
||||||
|
subtract_operand: &SubtractOperand,
|
||||||
|
registers: &[Value],
|
||||||
|
current_frame: &CallFrame,
|
||||||
|
) -> Value {
|
||||||
|
match subtract_operand {
|
||||||
|
SubtractOperand::Location(location) => load_value(
|
||||||
|
registers,
|
||||||
|
current_frame.stack(),
|
||||||
|
current_frame.fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
SubtractOperand::Int(i) => Value::Int(*i),
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,19 @@
|
|||||||
use crate::instruction::{
|
use crate::instruction::{AddOperand, Instruction, MoveOperand, PushOperand, ReturnOperand};
|
||||||
AddOperand, ConstantName, Instruction, Location, MoveOperand, PushOperand, ReturnOperand,
|
|
||||||
};
|
|
||||||
use crate::platform_function::PlatformFunction;
|
use crate::platform_function::PlatformFunction;
|
||||||
use crate::vm::constant::Constant;
|
use crate::vm::constant::Constant;
|
||||||
use crate::vm::function::Function;
|
use crate::vm::function::Function;
|
||||||
|
use crate::vm::instruction_helpers::subtract_operand_to_value;
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
|
use crate::vm::value_util::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
|
mod instruction_helpers;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
|
mod value_util;
|
||||||
|
|
||||||
pub struct DvmContext {
|
pub struct DvmContext {
|
||||||
functions: HashMap<Rc<str>, Function>,
|
functions: HashMap<Rc<str>, Function>,
|
||||||
@ -165,55 +167,6 @@ impl<'a> CallStack<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_value<'a>(
|
|
||||||
registers: &'a [Value],
|
|
||||||
stack: &'a [Value],
|
|
||||||
fp: usize,
|
|
||||||
location: &Location,
|
|
||||||
) -> &'a Value {
|
|
||||||
match location {
|
|
||||||
Location::Register(register) => ®isters[*register],
|
|
||||||
Location::StackFrameOffset(offset) => {
|
|
||||||
let value_index = fp.checked_add_signed(*offset).expect(&format!(
|
|
||||||
"Overflow when adding offset {} to fp {}",
|
|
||||||
*offset, fp
|
|
||||||
));
|
|
||||||
&stack[value_index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_constant_value(
|
|
||||||
constants: &HashMap<Rc<str>, Constant>,
|
|
||||||
constant_name: &ConstantName,
|
|
||||||
) -> Value {
|
|
||||||
let constant = &constants[constant_name];
|
|
||||||
match constant {
|
|
||||||
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put_value(
|
|
||||||
registers: &mut Vec<Value>,
|
|
||||||
stack: &mut Vec<Value>,
|
|
||||||
fp: usize,
|
|
||||||
destination: &Location,
|
|
||||||
value: Value,
|
|
||||||
) {
|
|
||||||
match destination {
|
|
||||||
Location::Register(register) => {
|
|
||||||
registers[*register] = value;
|
|
||||||
}
|
|
||||||
Location::StackFrameOffset(offset) => {
|
|
||||||
let target_index = fp.checked_add_signed(*offset).expect(&format!(
|
|
||||||
"Failed to calculate target index from fp + offset ({} + {})",
|
|
||||||
fp, offset
|
|
||||||
));
|
|
||||||
stack[target_index] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call<'a>(
|
pub fn call<'a>(
|
||||||
context: &'a DvmContext,
|
context: &'a DvmContext,
|
||||||
registers: &mut Vec<Value>,
|
registers: &mut Vec<Value>,
|
||||||
@ -277,14 +230,7 @@ pub fn call<'a>(
|
|||||||
load_constant_value(context.constants(), constant_name)
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let fp = call_stack.top().fp();
|
put_value(registers, call_stack.top_mut(), destination, value);
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut().stack_mut(),
|
|
||||||
fp,
|
|
||||||
destination,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,21 +347,17 @@ pub fn call<'a>(
|
|||||||
if let Value::Int(left) = left_value {
|
if let Value::Int(left) = left_value {
|
||||||
if let Value::Int(right) = right_value {
|
if let Value::Int(right) = right_value {
|
||||||
let result = left + right;
|
let result = left + right;
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::Int(result),
|
Value::Int(result),
|
||||||
);
|
);
|
||||||
} else if let Value::String(s) = right_value {
|
} else if let Value::String(s) = right_value {
|
||||||
let result = format!("{}{}", left, s);
|
let result = format!("{}{}", left, s);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
@ -425,21 +367,17 @@ pub fn call<'a>(
|
|||||||
} else if let Value::String(left) = left_value {
|
} else if let Value::String(left) = left_value {
|
||||||
if let Value::Int(right) = right_value {
|
if let Value::Int(right) = right_value {
|
||||||
let result = format!("{}{}", left, right);
|
let result = format!("{}{}", left, right);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
} else if let Value::String(right) = right_value {
|
} else if let Value::String(right) = right_value {
|
||||||
let result = format!("{}{}", left, right);
|
let result = format!("{}{}", left, right);
|
||||||
let fp = call_stack.top().fp();
|
|
||||||
put_value(
|
put_value(
|
||||||
registers,
|
registers,
|
||||||
call_stack.top_mut().stack_mut(),
|
call_stack.top_mut(),
|
||||||
fp,
|
|
||||||
destination,
|
destination,
|
||||||
Value::String(result.into()),
|
Value::String(result.into()),
|
||||||
);
|
);
|
||||||
@ -452,19 +390,21 @@ pub fn call<'a>(
|
|||||||
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
Instruction::Subtract(left_operand, right_operand, destination) => {
|
||||||
|
let left = subtract_operand_to_value(left_operand, registers, call_stack.top())
|
||||||
|
.unwrap_int();
|
||||||
|
let right = subtract_operand_to_value(right_operand, registers, call_stack.top())
|
||||||
|
.unwrap_int();
|
||||||
|
let result = Value::Int(left - right);
|
||||||
|
put_value(registers, call_stack.top_mut(), destination, result);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
|
}
|
||||||
|
|
||||||
/* Pop instructions */
|
/* Pop instructions */
|
||||||
Instruction::Pop(maybe_location) => {
|
Instruction::Pop(maybe_location) => {
|
||||||
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
||||||
if let Some(location) = maybe_location {
|
if let Some(location) = maybe_location {
|
||||||
let fp = call_stack.top().fp();
|
put_value(registers, call_stack.top_mut(), location, value);
|
||||||
put_value(
|
|
||||||
registers,
|
|
||||||
call_stack.top_mut().stack_mut(),
|
|
||||||
fp,
|
|
||||||
location,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|||||||
55
dvm-lib/src/vm/value_util.rs
Normal file
55
dvm-lib/src/vm/value_util.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::instruction::{ConstantName, Location};
|
||||||
|
use crate::vm::CallFrame;
|
||||||
|
use crate::vm::constant::Constant;
|
||||||
|
use crate::vm::value::Value;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub fn load_value<'a>(
|
||||||
|
registers: &'a [Value],
|
||||||
|
stack: &'a [Value],
|
||||||
|
fp: usize,
|
||||||
|
location: &Location,
|
||||||
|
) -> &'a Value {
|
||||||
|
match location {
|
||||||
|
Location::Register(register) => ®isters[*register],
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let value_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Overflow when adding offset {} to fp {}",
|
||||||
|
*offset, fp
|
||||||
|
));
|
||||||
|
&stack[value_index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_constant_value(
|
||||||
|
constants: &HashMap<Rc<str>, Constant>,
|
||||||
|
constant_name: &ConstantName,
|
||||||
|
) -> Value {
|
||||||
|
let constant = &constants[constant_name];
|
||||||
|
match constant {
|
||||||
|
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn put_value(
|
||||||
|
registers: &mut Vec<Value>,
|
||||||
|
current_frame: &mut CallFrame,
|
||||||
|
destination: &Location,
|
||||||
|
value: Value,
|
||||||
|
) {
|
||||||
|
match destination {
|
||||||
|
Location::Register(register) => {
|
||||||
|
registers[*register] = value;
|
||||||
|
}
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let fp = current_frame.fp();
|
||||||
|
let target_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Failed to calculate target index from fp + offset ({} + {})",
|
||||||
|
fp, offset
|
||||||
|
));
|
||||||
|
current_frame.stack_mut()[target_index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,19 +35,25 @@ mod e2e_tests {
|
|||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
|
||||||
let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table);
|
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||||
if !gather_names_diagnostics.is_empty() {
|
Ok(_) => {}
|
||||||
report_diagnostics(&gather_names_diagnostics);
|
Err(diagnostics) => {
|
||||||
|
report_diagnostics(&diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table);
|
match compilation_unit.check_name_usages(&symbol_table) {
|
||||||
if !name_usages_diagnostics.is_empty() {
|
Ok(_) => {}
|
||||||
report_diagnostics(&name_usages_diagnostics);
|
Err(diagnostics) => {
|
||||||
|
report_diagnostics(&diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
match compilation_unit.type_check(&symbol_table) {
|
||||||
if !type_check_diagnostics.is_empty() {
|
Ok(_) => {}
|
||||||
report_diagnostics(&type_check_diagnostics);
|
Err(diagnostics) => {
|
||||||
|
report_diagnostics(&diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||||
@ -125,4 +131,9 @@ mod e2e_tests {
|
|||||||
Value::String(Rc::from("Hello. 1 plus 2 is 3")),
|
Value::String(Rc::from("Hello. 1 plus 2 is 3")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_subtract() {
|
||||||
|
assert_result("fn sub() -> Int 3 - 2 end", "sub", &vec![], Value::Int(1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
examples/subtract.dm
Normal file
16
examples/subtract.dm
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn add(a: Int, b: Int) -> Int
|
||||||
|
a + b
|
||||||
|
end
|
||||||
|
|
||||||
|
fn subtract(a: Int, b: Int) -> Int
|
||||||
|
a - b
|
||||||
|
end
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
let a = 42
|
||||||
|
let b = 42
|
||||||
|
println(add(a, b))
|
||||||
|
println(subtract(a, b))
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user