Bunch of AST refactoring to make api easier.
This commit is contained in:
parent
9d09f7481b
commit
e35bacb583
@ -47,14 +47,26 @@ fn main() {
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
|
||||
let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table);
|
||||
check_and_report_diagnostics(&files, script_file_id, &gather_names_diagnostics);
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table);
|
||||
check_and_report_diagnostics(&files, script_file_id, &name_usages_diagnostics);
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
||||
check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics);
|
||||
match compilation_unit.type_check(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_and_exit(&diagnostics, script_file_id, &files);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||
|
||||
@ -118,6 +130,15 @@ fn check_and_report_diagnostics(
|
||||
diagnostics: &[Diagnostic],
|
||||
) {
|
||||
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 config = term::Config::default();
|
||||
for diagnostic in diagnostics {
|
||||
@ -139,5 +160,4 @@ fn check_and_report_diagnostics(
|
||||
);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,18 +6,20 @@ use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct AdditiveExpression {
|
||||
pub struct AddExpression {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
source_range: SourceRange,
|
||||
type_info: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl AdditiveExpression {
|
||||
impl AddExpression {
|
||||
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
||||
Self {
|
||||
lhs: lhs.into(),
|
||||
rhs: rhs.into(),
|
||||
source_range,
|
||||
type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,9 +35,12 @@ impl AdditiveExpression {
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.lhs.gather_declared_names(symbol_table));
|
||||
diagnostics.append(&mut self.rhs.gather_declared_names(symbol_table));
|
||||
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
|
||||
.iter_mut()
|
||||
.map(|expression| expression.gather_declared_names(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -44,9 +49,12 @@ impl AdditiveExpression {
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.lhs.check_name_usages(symbol_table));
|
||||
diagnostics.append(&mut self.rhs.check_name_usages(symbol_table));
|
||||
let diagnostics: Vec<Diagnostic> = [self.lhs.as_mut(), self.rhs.as_mut()]
|
||||
.iter_mut()
|
||||
.map(|expression| expression.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -55,12 +63,13 @@ impl AdditiveExpression {
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.lhs.type_check(symbol_table);
|
||||
self.rhs.type_check(symbol_table);
|
||||
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_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(())
|
||||
} else {
|
||||
Err(vec![Diagnostic::new(
|
||||
@ -83,8 +92,8 @@ impl AdditiveExpression {
|
||||
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> TypeInfo {
|
||||
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
@ -14,6 +14,7 @@ pub struct Call {
|
||||
callee: Box<Expression>,
|
||||
arguments: Vec<Expression>,
|
||||
source_range: SourceRange,
|
||||
return_type_info: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl Call {
|
||||
@ -22,6 +23,7 @@ impl Call {
|
||||
callee: callee.into(),
|
||||
arguments,
|
||||
source_range,
|
||||
return_type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,44 +35,74 @@ impl Call {
|
||||
self.arguments.iter().collect()
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.callee.gather_declared_names(symbol_table));
|
||||
for argument in &mut self.arguments {
|
||||
diagnostics.append(&mut argument.gather_declared_names(symbol_table));
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
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> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.callee.check_name_usages(symbol_table));
|
||||
for argument in &mut self.arguments {
|
||||
diagnostics.append(&mut argument.check_name_usages(symbol_table));
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut to_check = vec![];
|
||||
to_check.push(self.callee.as_mut());
|
||||
to_check.extend(&mut self.arguments);
|
||||
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> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.append(&mut self.callee.type_check(symbol_table));
|
||||
for argument in &mut self.arguments {
|
||||
diagnostics.append(&mut argument.type_check(symbol_table));
|
||||
}
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.callee.as_mut().type_check(symbol_table)?;
|
||||
|
||||
let mut diagnostics: Vec<Diagnostic> = self
|
||||
.arguments
|
||||
.iter_mut()
|
||||
.map(|argument| argument.type_check(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
// check that callee is callable
|
||||
let function_symbol = match self.callee.type_info() {
|
||||
TypeInfo::Function(function_symbol) => function_symbol,
|
||||
_ => {
|
||||
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().end(),
|
||||
));
|
||||
return diagnostics;
|
||||
return Err(diagnostics);
|
||||
}
|
||||
};
|
||||
|
||||
// set return type
|
||||
self.return_type_info = Some(function_symbol.borrow().return_type_info().clone());
|
||||
|
||||
// check arguments length
|
||||
let function_symbol_ref = function_symbol.borrow();
|
||||
let parameters = function_symbol_ref.parameters();
|
||||
@ -87,23 +119,20 @@ impl Call {
|
||||
}
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
return diagnostics;
|
||||
return Err(diagnostics);
|
||||
}
|
||||
|
||||
// check argument types
|
||||
for i in 0..parameters.len() {
|
||||
let parameter = ¶meters[i];
|
||||
let parameter = ¶meters[i].borrow();
|
||||
let argument = &self.arguments[i];
|
||||
if !parameter
|
||||
.borrow()
|
||||
.type_info()
|
||||
.is_assignable_from(&argument.type_info())
|
||||
{
|
||||
let parameter_type_info = parameter.type_info();
|
||||
let argument_type_info = argument.type_info();
|
||||
if !parameter_type_info.is_assignable_from(argument_type_info) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
&format!(
|
||||
"Mismatched types; expected {} but found {}",
|
||||
parameter.borrow().type_info(),
|
||||
argument.type_info()
|
||||
"Mismatched types: expected {} but found {}",
|
||||
parameter_type_info, argument_type_info
|
||||
),
|
||||
argument.source_range().start(),
|
||||
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 {
|
||||
match self.callee.type_info() {
|
||||
TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(),
|
||||
_ => panic!(),
|
||||
}
|
||||
pub fn return_type_info(&self) -> &TypeInfo {
|
||||
self.return_type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn get_callee_symbol(&self) -> Rc<RefCell<FunctionSymbol>> {
|
||||
|
||||
@ -16,30 +16,57 @@ impl CompilationUnit {
|
||||
&self.declarations
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
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();
|
||||
diagnostics
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
for declaration in &mut self.declarations {
|
||||
diagnostics.append(&mut declaration.check_name_usages(symbol_table));
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
.declarations
|
||||
.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> {
|
||||
let mut diagnostics = vec![];
|
||||
for declaration in &mut self.declarations {
|
||||
diagnostics.append(&mut declaration.type_check(symbol_table));
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
.declarations
|
||||
.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> {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::ast::additive_expression::AdditiveExpression;
|
||||
use crate::ast::add_expression::AddExpression;
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::identifier::Identifier;
|
||||
use crate::ast::integer_literal::IntegerLiteral;
|
||||
@ -19,84 +19,88 @@ use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum Expression {
|
||||
Call(Call),
|
||||
IntegerLiteral(IntegerLiteral),
|
||||
String(StringLiteral),
|
||||
Identifier(Identifier),
|
||||
Additive(AdditiveExpression),
|
||||
Add(AddExpression),
|
||||
Subtract(SubtractExpression),
|
||||
Negative(NegativeExpression),
|
||||
Call(Call),
|
||||
Identifier(Identifier),
|
||||
Integer(IntegerLiteral),
|
||||
String(StringLiteral),
|
||||
}
|
||||
|
||||
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 {
|
||||
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::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
||||
Expression::Additive(additive_expression) => {
|
||||
match additive_expression.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
Expression::Integer(_) => Ok(()),
|
||||
Expression::String(_) => 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>> {
|
||||
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::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
||||
Expression::Additive(additive_expression) => {
|
||||
match additive_expression.check_name_usages(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
Expression::Integer(_) => Ok(()),
|
||||
Expression::String(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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::Additive(additive_expression) => {
|
||||
match additive_expression.type_check(symbol_table) {
|
||||
Ok(_) => {
|
||||
vec![]
|
||||
}
|
||||
Err(diagnostics) => diagnostics,
|
||||
}
|
||||
}
|
||||
_ => vec![],
|
||||
Expression::Identifier(identifier) => identifier.type_check(symbol_table),
|
||||
Expression::Integer(_) => Ok(()),
|
||||
Expression::String(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> TypeInfo {
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
match self {
|
||||
Expression::Call(call) => call.type_info(),
|
||||
Expression::IntegerLiteral(_) => TypeInfo::Integer,
|
||||
Expression::String(_) => TypeInfo::String,
|
||||
Expression::Add(add_expression) => add_expression.type_info(),
|
||||
Expression::Subtract(subtract_expression) => subtract_expression.type_info(),
|
||||
Expression::Negative(negative_expression) => negative_expression.type_info(),
|
||||
Expression::Call(call) => call.return_type_info(),
|
||||
Expression::Identifier(identifier) => identifier.type_info(),
|
||||
Expression::Additive(additive_expression) => additive_expression.type_info(),
|
||||
Expression::Subtract(subtract_expression) => todo!(),
|
||||
Expression::Negative(_) => todo!(),
|
||||
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
||||
Expression::String(string_literal) => string_literal.type_info(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
match self {
|
||||
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::Additive(additive_expression) => additive_expression.source_range(),
|
||||
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::Identifier(identifier) => identifier.source_range(),
|
||||
Expression::Integer(integer_literal) => integer_literal.source_range(),
|
||||
Expression::String(string_literal) => string_literal.source_range(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +112,7 @@ impl Expression {
|
||||
match self {
|
||||
Expression::Call(call) => {
|
||||
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
|
||||
.current_block_mut()
|
||||
.add_statement(IrStatement::Call(ir_call));
|
||||
@ -117,7 +121,7 @@ impl Expression {
|
||||
let t_var = IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
builder.current_block().id(),
|
||||
call.type_info(),
|
||||
call.return_type_info(),
|
||||
);
|
||||
let as_rc = Rc::new(RefCell::new(t_var));
|
||||
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
||||
@ -127,7 +131,7 @@ impl Expression {
|
||||
Some(IrExpression::Variable(as_rc))
|
||||
}
|
||||
}
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
Some(IrExpression::Int(integer_literal.value()))
|
||||
}
|
||||
Expression::String(string_literal) => {
|
||||
@ -137,7 +141,7 @@ impl Expression {
|
||||
let expressible_symbol = identifier.expressible_symbol();
|
||||
Some(expressible_symbol.ir_expression())
|
||||
}
|
||||
Expression::Additive(additive_expression) => {
|
||||
Expression::Add(additive_expression) => {
|
||||
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
||||
let t_var = IrVariable::new_vr(
|
||||
builder.new_t_var().into(),
|
||||
|
||||
@ -20,15 +20,18 @@ impl ExpressionStatement {
|
||||
&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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,10 @@ impl ExternFunction {
|
||||
&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 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.end(),
|
||||
));
|
||||
diagnostics
|
||||
Err(diagnostics)
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -79,24 +82,40 @@ impl ExternFunction {
|
||||
|
||||
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> {
|
||||
self.parameters
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect()
|
||||
.collect();
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
self.parameters
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.type_check(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect()
|
||||
.collect();
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,10 @@ impl Function {
|
||||
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![];
|
||||
|
||||
// insert function symbol
|
||||
@ -75,7 +78,7 @@ impl Function {
|
||||
self.declared_name_source_range.start(),
|
||||
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));
|
||||
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(); // 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![];
|
||||
|
||||
// parameters
|
||||
@ -126,12 +139,22 @@ impl Function {
|
||||
|
||||
// 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![];
|
||||
|
||||
// parameters
|
||||
@ -140,17 +163,27 @@ impl Function {
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.type_check(symbol_table))
|
||||
.filter_map(|result| result.err())
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// statements
|
||||
for statement in &mut self.statements {
|
||||
diagnostics.append(&mut statement.type_check(symbol_table));
|
||||
}
|
||||
diagnostics.append(
|
||||
&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 {
|
||||
@ -172,12 +205,8 @@ impl Function {
|
||||
|
||||
let entry_block_id = builder.new_block();
|
||||
|
||||
let return_type_info = self
|
||||
.function_symbol
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.return_type();
|
||||
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
||||
let return_type_info = function_symbol.return_type_info();
|
||||
|
||||
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ pub struct Identifier {
|
||||
name: String,
|
||||
scope_id: Option<usize>,
|
||||
expressible_symbol: Option<ExpressibleSymbol>,
|
||||
type_info: Option<TypeInfo>,
|
||||
source_range: SourceRange,
|
||||
}
|
||||
|
||||
@ -17,6 +18,7 @@ impl Identifier {
|
||||
name: name.into(),
|
||||
scope_id: None,
|
||||
expressible_symbol: None,
|
||||
type_info: None,
|
||||
source_range,
|
||||
}
|
||||
}
|
||||
@ -25,41 +27,38 @@ impl Identifier {
|
||||
&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());
|
||||
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 =
|
||||
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
|
||||
match maybe_expressible_symbol {
|
||||
None => {
|
||||
vec![Diagnostic::new(
|
||||
None => Err(vec![Diagnostic::new(
|
||||
&format!("Unable to resolve symbol {}", self.name),
|
||||
self.source_range.start(),
|
||||
self.source_range.end(),
|
||||
)]
|
||||
}
|
||||
)]),
|
||||
Some(expressible_symbol) => {
|
||||
self.expressible_symbol = Some(expressible_symbol);
|
||||
vec![]
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> TypeInfo {
|
||||
match self.expressible_symbol.as_ref().unwrap() {
|
||||
ExpressibleSymbol::Function(function_symbol) => {
|
||||
TypeInfo::Function(function_symbol.clone())
|
||||
}
|
||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||
parameter_symbol.borrow().type_info().clone()
|
||||
}
|
||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||
variable_symbol.borrow().type_info().clone()
|
||||
}
|
||||
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let type_info = self.expressible_symbol.as_ref().unwrap().type_info();
|
||||
self.type_info = Some(type_info);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn expressible_symbol(&self) -> &ExpressibleSymbol {
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct IntegerLiteral {
|
||||
value: i32,
|
||||
source_range: SourceRange,
|
||||
type_info: &'static TypeInfo,
|
||||
}
|
||||
|
||||
impl IntegerLiteral {
|
||||
pub fn new(value: i32, source_range: SourceRange) -> Self {
|
||||
const TYPE_INFO: TypeInfo = TypeInfo::Integer;
|
||||
Self {
|
||||
value,
|
||||
source_range,
|
||||
type_info: &TYPE_INFO,
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +21,10 @@ impl IntegerLiteral {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
&self.type_info
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
@ -45,9 +45,19 @@ impl LetStatement {
|
||||
&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![];
|
||||
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 =
|
||||
symbol_table.insert_variable_symbol(VariableSymbol::new(self.declared_name()));
|
||||
if let Err(symbol_insert_error) = insert_result {
|
||||
@ -64,32 +74,35 @@ impl LetStatement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||
let initializer_diagnostics = self.initializer.type_check(symbol_table);
|
||||
if !initializer_diagnostics.is_empty() {
|
||||
return initializer_diagnostics;
|
||||
}
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.initializer.type_check(symbol_table)?;
|
||||
let initializer_type_info = self.initializer.type_info();
|
||||
let variable_symbol =
|
||||
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
||||
variable_symbol
|
||||
.borrow_mut()
|
||||
.set_type_info(initializer_type_info);
|
||||
vec![]
|
||||
.set_type_info(initializer_type_info.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
||||
let init_operation = match self.initializer() {
|
||||
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()))
|
||||
}
|
||||
Expression::String(string_literal) => {
|
||||
@ -98,7 +111,7 @@ impl LetStatement {
|
||||
Expression::Identifier(identifier) => {
|
||||
IrOperation::Load(identifier.expressible_symbol().ir_expression())
|
||||
}
|
||||
Expression::Additive(additive_expression) => {
|
||||
Expression::Add(additive_expression) => {
|
||||
IrOperation::Add(additive_expression.to_ir(builder, symbol_table))
|
||||
}
|
||||
Expression::Subtract(subtract_expression) => todo!(),
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pub mod additive_expression;
|
||||
pub mod add_expression;
|
||||
pub mod call;
|
||||
pub mod compilation_unit;
|
||||
pub mod expression;
|
||||
|
||||
@ -9,7 +9,10 @@ pub enum 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 {
|
||||
ModuleLevelDeclaration::Function(function) => {
|
||||
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 {
|
||||
ModuleLevelDeclaration::Function(function) => function.check_name_usages(symbol_table),
|
||||
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 {
|
||||
ModuleLevelDeclaration::Function(function) => function.type_check(symbol_table),
|
||||
ModuleLevelDeclaration::ExternFunction(extern_function) => {
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
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 {
|
||||
@ -11,6 +15,7 @@ impl NegativeExpression {
|
||||
Self {
|
||||
operand: operand.into(),
|
||||
source_range,
|
||||
type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,4 +30,35 @@ impl NegativeExpression {
|
||||
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 {
|
||||
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 {
|
||||
Statement::Let(let_statement) => let_statement.gather_declared_names(symbol_table),
|
||||
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 {
|
||||
Statement::Let(let_statement) => let_statement.check_name_usages(symbol_table),
|
||||
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 {
|
||||
Statement::Let(let_statement) => let_statement.type_check(symbol_table),
|
||||
Statement::Expression(expression_statement) => {
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct StringLiteral {
|
||||
content: String,
|
||||
source_range: SourceRange,
|
||||
type_info: &'static TypeInfo,
|
||||
}
|
||||
|
||||
impl StringLiteral {
|
||||
pub fn new(content: &str, source_range: SourceRange) -> Self {
|
||||
const TYPE_INFO: TypeInfo = TypeInfo::Integer;
|
||||
Self {
|
||||
content: content.into(),
|
||||
source_range,
|
||||
type_info: &TYPE_INFO,
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +21,10 @@ impl StringLiteral {
|
||||
&self.content
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
&self.type_info
|
||||
}
|
||||
|
||||
pub fn source_range(&self) -> &SourceRange {
|
||||
&self.source_range
|
||||
}
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
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 SubtractExpression {
|
||||
lhs: Box<Expression>,
|
||||
rhs: Box<Expression>,
|
||||
source_range: SourceRange,
|
||||
type_info: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl SubtractExpression {
|
||||
@ -13,6 +17,7 @@ impl SubtractExpression {
|
||||
lhs: lhs.into(),
|
||||
rhs: rhs.into(),
|
||||
source_range,
|
||||
type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +29,62 @@ impl SubtractExpression {
|
||||
&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
|
||||
}
|
||||
|
||||
@ -23,13 +23,13 @@ impl IrFunction {
|
||||
pub fn new(
|
||||
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||
parameters: &[Rc<IrParameter>],
|
||||
return_type_info: TypeInfo,
|
||||
return_type_info: &TypeInfo,
|
||||
entry: Rc<RefCell<IrBlock>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
function_symbol,
|
||||
parameters: parameters.to_vec(),
|
||||
return_type_info,
|
||||
return_type_info: return_type_info.clone(),
|
||||
entry,
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,19 +9,19 @@ pub struct 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 {
|
||||
descriptor: IrVariableDescriptor::VirtualRegister(IrVrVariableDescriptor::new(
|
||||
name, block_id,
|
||||
)),
|
||||
type_info,
|
||||
type_info: type_info.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_stack(name: Rc<str>, block_id: usize, type_info: TypeInfo) -> Self {
|
||||
Self {
|
||||
descriptor: IrVariableDescriptor::Stack(IrStackVariableDescriptor::new(name, block_id)),
|
||||
type_info,
|
||||
type_info: type_info.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::ast::additive_expression::AdditiveExpression;
|
||||
use crate::ast::add_expression::AddExpression;
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::expression::Expression;
|
||||
@ -408,8 +408,7 @@ impl<'a> Parser<'a> {
|
||||
let rhs = self.prefix_expression()?;
|
||||
let source_range =
|
||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||
result =
|
||||
Expression::Additive(AdditiveExpression::new(result, rhs, source_range));
|
||||
result = Expression::Add(AddExpression::new(result, rhs, source_range));
|
||||
}
|
||||
TokenKind::Minus => {
|
||||
self.advance(); // minus
|
||||
@ -477,7 +476,7 @@ impl<'a> Parser<'a> {
|
||||
let raw = self.token_text(¤t);
|
||||
let source_range = SourceRange::new(current.start(), current.end());
|
||||
self.advance();
|
||||
Ok(Expression::IntegerLiteral(IntegerLiteral::new(
|
||||
Ok(Expression::Integer(IntegerLiteral::new(
|
||||
i32::from_str(raw).unwrap(),
|
||||
source_range,
|
||||
)))
|
||||
@ -716,7 +715,7 @@ mod concrete_tests {
|
||||
let expression = assert_expression("-1");
|
||||
match expression {
|
||||
Expression::Negative(negative_expression) => match negative_expression.operand() {
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
assert_eq!(integer_literal.value(), 1);
|
||||
}
|
||||
_ => panic!("Expected integer literal"),
|
||||
@ -729,9 +728,9 @@ mod concrete_tests {
|
||||
fn add_negative() {
|
||||
let expression = assert_expression("1 + -1");
|
||||
match expression {
|
||||
Expression::Additive(add_expression) => {
|
||||
Expression::Add(add_expression) => {
|
||||
match add_expression.lhs() {
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
assert_eq!(integer_literal.value(), 1);
|
||||
}
|
||||
_ => panic!("Expected integer literal"),
|
||||
@ -739,7 +738,7 @@ mod concrete_tests {
|
||||
match add_expression.rhs() {
|
||||
Expression::Negative(negative_expression) => {
|
||||
match negative_expression.operand() {
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
assert_eq!(integer_literal.value(), 1);
|
||||
}
|
||||
_ => panic!("Expected integer literal"),
|
||||
@ -758,13 +757,13 @@ mod concrete_tests {
|
||||
match expression {
|
||||
Expression::Subtract(subtract_expression) => {
|
||||
match subtract_expression.lhs() {
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
assert_eq!(integer_literal.value(), 1);
|
||||
}
|
||||
_ => panic!("Expected integer literal"),
|
||||
}
|
||||
match subtract_expression.rhs() {
|
||||
Expression::IntegerLiteral(integer_literal) => {
|
||||
Expression::Integer(integer_literal) => {
|
||||
assert_eq!(integer_literal.value(), 1);
|
||||
}
|
||||
_ => panic!("Expected integer literal"),
|
||||
|
||||
@ -38,8 +38,8 @@ impl FunctionSymbol {
|
||||
self.parameters.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn return_type(&self) -> TypeInfo {
|
||||
self.return_type.clone()
|
||||
pub fn return_type_info(&self) -> &TypeInfo {
|
||||
&self.return_type
|
||||
}
|
||||
|
||||
pub fn is_platform(&self) -> bool {
|
||||
@ -134,6 +134,20 @@ pub enum 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 {
|
||||
match self {
|
||||
ExpressibleSymbol::Function(_) => {
|
||||
|
||||
@ -68,11 +68,36 @@ impl TypeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn additive_result(&self, _rhs: &Self) -> TypeInfo {
|
||||
pub fn add_result(&self, _rhs: &Self) -> TypeInfo {
|
||||
match self {
|
||||
TypeInfo::Integer => TypeInfo::Integer,
|
||||
TypeInfo::String => TypeInfo::String,
|
||||
_ => 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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,19 +35,25 @@ mod e2e_tests {
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
|
||||
let gather_names_diagnostics = compilation_unit.gather_declared_names(&mut symbol_table);
|
||||
if !gather_names_diagnostics.is_empty() {
|
||||
report_diagnostics(&gather_names_diagnostics);
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_diagnostics(&diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
let name_usages_diagnostics = compilation_unit.check_name_usages(&symbol_table);
|
||||
if !name_usages_diagnostics.is_empty() {
|
||||
report_diagnostics(&name_usages_diagnostics);
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_diagnostics(&diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
||||
if !type_check_diagnostics.is_empty() {
|
||||
report_diagnostics(&type_check_diagnostics);
|
||||
match compilation_unit.type_check(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
report_diagnostics(&diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user