Clean out old original implementations of ast passes.

This commit is contained in:
Jesse Brault 2026-08-13 17:46:13 -05:00
parent 826c9fb2b7
commit e7145de68e
31 changed files with 21 additions and 6678 deletions

View File

@ -1,24 +1,4 @@
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::ir_util::get_or_init_mut_field_pointer_variable;
use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics, SecondaryLabel};
use crate::diagnostic_factories::{
destination_must_be_mutable, mismatched_assign_types, must_be_l_value,
};
use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_set_field::IrSetField;
use crate::ir::ir_statement::IrStatement;
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
use std::collections::HashSet;
use std::rc::Rc;
pub struct AssignStatement { pub struct AssignStatement {
destination: Box<Expression>, destination: Box<Expression>,
@ -40,513 +20,4 @@ impl AssignStatement {
pub fn value(&self) -> &Expression { pub fn value(&self) -> &Expression {
&self.value &self.value
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.destination.init_scopes(symbol_table, container_scope);
self.value.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.destination.as_ref(), self.value.as_ref()] {
let (ns, mut ds) = expression.resolve_names_static(symbol_table);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
.value
.resolve_names_ctor(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
match self.destination.as_ref() {
Expression::Identifier(identifier) => {
let (ns, mut ds) =
identifier.resolve_name_ctor_destination(symbol_table, initialized_fields);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
_ => {
// no-op, because this is a non-L-Value and will be caught during type checking.
}
}
(names_table, diagnostics)
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.destination.as_ref(), self.value.as_ref()] {
let (ns, mut ds) = expression.resolve_names_method(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
[
self.destination
.check_constructor_destination_names(symbol_table, class_symbol),
self.value
.check_constructor_local_names(symbol_table, class_symbol),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
[
self.destination
.check_method_local_names(symbol_table, class_symbol),
self.value
.check_method_local_names(symbol_table, class_symbol),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
[
self.destination.check_static_fn_local_names(symbol_table),
self.value.check_static_fn_local_names(symbol_table),
]
.into_iter()
.flatten()
.collect()
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_types = NodesToTypes::new();
{
let (nts, mut ds) = self.value.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
{
let (nts, mut ds) = self
.destination
.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
// check that destination is L value, mutable, and assignable
match &*self.destination {
// must be identifier (for now)
Expression::Identifier(identifier) => {
let expressible_symbol = nodes_to_symbols
.get(&identifier.node_id())
.unwrap()
.unwrap_expressible_symbol();
let is_mut = match &expressible_symbol {
ExpressibleSymbol::Field(field_symbol) => field_symbol.is_mut(),
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.is_mut(),
_ => false,
};
// check mut
if !is_mut {
diagnostics.push(destination_must_be_mutable(
self.destination.source_range(),
expressible_symbol.source_range(),
));
}
let maybe_expressible_symbol_source_range =
expressible_symbol.source_range().cloned();
let lhs_type = symbols_to_types
.get(&expressible_symbol.into_symbol())
.unwrap();
let rhs_type = nodes_to_types.get(&self.value.node_id()).unwrap();
// check assignable
if !lhs_type.is_assignable_from(rhs_type) {
diagnostics.push(mismatched_assign_types(
rhs_type,
lhs_type,
&SourceRange::new(
self.destination.source_range().start(),
self.value.source_range().end(),
),
maybe_expressible_symbol_source_range.as_ref(),
));
}
}
_ => {
diagnostics.push(must_be_l_value(self.destination.source_range()));
}
}
(nodes_to_types, diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
match self.value.type_check(symbol_table, types_table) {
Ok(_) => {}
Err(mut value_diagnostics) => {
diagnostics.append(&mut value_diagnostics);
}
}
match self.destination.type_check(symbol_table, types_table) {
Ok(_) => {}
Err(mut destination_diagnostics) => {
diagnostics.append(&mut destination_diagnostics);
}
}
// check destination is l value
match &*self.destination {
Expression::Identifier(identifier) => {
let expressible_symbol = symbol_table
.find_expressible_symbol(identifier.scope_id(), identifier.name())
.unwrap();
let is_mut = match &expressible_symbol {
ExpressibleSymbol::Field(field_symbol) => field_symbol.is_mut(),
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.is_mut(),
_ => false,
};
// check mutable
if !is_mut {
let secondary_label =
if let Some(source_range) = expressible_symbol.source_range() {
Some(SecondaryLabel::new(
source_range.start(),
source_range.end(),
Some("Destination (declared here) is immutable.".to_string()),
))
} else {
None
};
let mut diagnostic = Diagnostic::new(
"Destination is immutable and not re-assignable.",
self.destination.source_range().start(),
self.destination.source_range().end(),
)
.with_primary_label_message("Attempt to mutate immutable destination.")
.with_reporter(file!(), line!())
.with_error_code(ASSIGN_LHS_IMMUTABLE);
if let Some(secondary_label) = secondary_label {
diagnostic = diagnostic.with_secondary_labels(&[secondary_label]);
}
diagnostics.push(diagnostic);
}
// check assignable
let lhs_type = match &expressible_symbol {
ExpressibleSymbol::Field(field_symbol) => {
types_table.field_types().get(field_symbol).unwrap()
}
ExpressibleSymbol::Variable(variable_symbol) => {
types_table.variable_types().get(variable_symbol).unwrap()
}
_ => panic!(),
};
let rhs_type = self.value.type_info(symbol_table, types_table);
if !lhs_type.is_assignable_from(rhs_type) {
let secondary_label =
if let Some(source_range) = expressible_symbol.source_range() {
Some(SecondaryLabel::new(
source_range.start(),
source_range.end(),
Some(format!(
"Destination declared here is of type {}.",
lhs_type
)),
))
} else {
None
};
let mut diagnostic = Diagnostic::new(
&format!(
"Mismatched types: right-hand side {} is not assignable to left {}.",
rhs_type, lhs_type
),
self.destination.source_range().start(),
self.value.source_range().end(),
)
.with_primary_label_message(&format!(
"Attempt to assign {} to {}.",
rhs_type, lhs_type
))
.with_error_code(ASSIGN_MISMATCHED_TYPES)
.with_reporter(file!(), line!());
if let Some(secondary_label) = secondary_label {
diagnostic = diagnostic.with_secondary_labels(&[secondary_label]);
}
diagnostics.push(diagnostic);
}
}
_ => {
let diagnostic = Diagnostic::new(
"Left-hand side of assign must be an L value.",
self.destination.source_range().start(),
self.destination.source_range().end(),
)
.with_primary_label_message("Must be L value.")
.with_reporter(file!(), line!())
.with_error_code(ASSIGN_NO_L_VALUE);
diagnostics.push(diagnostic);
}
}
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
#[deprecated]
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) {
let destination_symbol = match &*self.destination {
Expression::Identifier(identifier) => symbol_table
.find_expressible_symbol(identifier.scope_id(), identifier.name())
.unwrap(),
_ => unreachable!("Destination must be a mutable L value"),
};
let ir_statement = match destination_symbol {
ExpressibleSymbol::Field(field_symbol) => {
let field_type = types_table.field_types().get(&field_symbol).unwrap();
let mut_field_pointer_variable =
get_or_init_mut_field_pointer_variable(builder, &field_symbol, field_type)
.clone();
let ir_set_field = IrSetField::new(
todo!(),
self.value
.to_ir_expression(builder, symbol_table, types_table)
.expect("Attempt to convert non-value to value"),
);
IrStatement::SetField(ir_set_field)
}
ExpressibleSymbol::Variable(variable_symbol) => {
let vr_variable = builder.local_variables().get(&variable_symbol).unwrap();
let ir_assign = IrAssign::new(
todo!(),
self.value
.to_ir_operation(builder, symbol_table, types_table),
);
IrStatement::Assign(ir_assign)
}
_ => unreachable!("Destination must be a mutable L value"),
};
builder.current_block_mut().add_statement(ir_statement);
}
pub fn lower_to_ir(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) {
let destination_expressible_symbol = match self.destination.as_ref() {
Expression::Identifier(identifier) => nodes_to_symbols
.get(&identifier.scope_id())
.unwrap()
.unwrap_expressible_symbol(),
_ => unreachable!("Destination must be a mutable L value"),
};
let ir_statement = match destination_expressible_symbol {
ExpressibleSymbol::Field(field_symbol) => {
let field_type = symbols_to_types
.get(&Symbol::Field(field_symbol.clone()))
.unwrap();
let mut_field_pointer_variable =
get_or_init_mut_field_pointer_variable(builder, &field_symbol, field_type)
.clone();
let ir_set_field = IrSetField::new(
todo!(),
self.value.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
),
);
IrStatement::SetField(ir_set_field)
}
ExpressibleSymbol::Variable(variable_symbol) => {
let ir_variable = builder.local_variables().get(&variable_symbol).unwrap();
let ir_assign = IrAssign::new(
todo!(),
self.value.lower_to_ir_operation(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
),
);
IrStatement::Assign(ir_assign)
}
_ => unreachable!("Destination must be a mutable L value"),
};
builder.current_block_mut().add_statement(ir_statement);
}
}
#[cfg(test)]
mod tests {
use crate::ast::compilation_unit::CompilationUnit;
use crate::diagnostic::Diagnostic;
use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
use crate::parser::get_compilation_unit;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
fn compile_up_to_type_check(
compilation_unit: &mut CompilationUnit,
symbol_table: &mut SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
compilation_unit.init_scopes(symbol_table);
compilation_unit.gather_symbols_into(symbol_table)?;
compilation_unit.check_names(symbol_table)?;
compilation_unit.gather_types_into(symbol_table, types_table)
}
#[test]
fn finds_mismatched_types() -> Result<(), Vec<Diagnostic>> {
let mut compilation_unit = get_compilation_unit(
"
fn main()
let mut x = 4
x = \"Hello\"
end
",
None,
)?;
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table, &mut types_table)?;
let diagnostics = compilation_unit
.type_check(&symbol_table, &mut types_table)
.unwrap_err();
assert_eq!(diagnostics.len(), 1);
assert_eq!(
diagnostics[0].error_code().unwrap(),
ASSIGN_MISMATCHED_TYPES
);
Ok(())
}
#[test]
fn finds_no_l_value() -> Result<(), Vec<Diagnostic>> {
let mut compilation_unit = get_compilation_unit(
"
fn main()
42 = 42
end
",
None,
)?;
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table, &mut types_table)?;
let diagnostics = compilation_unit
.type_check(&symbol_table, &mut types_table)
.unwrap_err();
assert_eq!(diagnostics.len(), 1);
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_NO_L_VALUE);
Ok(())
}
#[test]
fn finds_immutable_destination() -> Result<(), Vec<Diagnostic>> {
let mut compilation_unit = get_compilation_unit(
"
fn main()
let x = 42
x = 43
end
",
None,
)?;
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table, &mut types_table)?;
let diagnostics = compilation_unit
.type_check(&symbol_table, &mut types_table)
.unwrap_err();
assert_eq!(diagnostics.len(), 1);
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_LHS_IMMUTABLE);
Ok(())
}
} }

View File

@ -1,23 +1,6 @@
use crate::ast::NodeId;
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::error_codes::BINARY_INCOMPATIBLE_TYPES;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostic, handle_diagnostics, maybe_return_diagnostics};
use std::cell::RefCell;
use std::rc::Rc;
pub enum BinaryOperation { pub enum BinaryOperation {
Multiply, Multiply,
@ -38,7 +21,6 @@ pub struct BinaryExpression {
rhs: Box<Expression>, rhs: Box<Expression>,
op: BinaryOperation, op: BinaryOperation,
source_range: SourceRange, source_range: SourceRange,
type_info: Option<TypeInfo>,
} }
impl BinaryExpression { impl BinaryExpression {
@ -55,7 +37,6 @@ impl BinaryExpression {
rhs: rhs.into(), rhs: rhs.into(),
op, op,
source_range, source_range,
type_info: None,
} }
} }
@ -78,558 +59,4 @@ impl BinaryExpression {
pub fn source_range(&self) -> &SourceRange { pub fn source_range(&self) -> &SourceRange {
&self.source_range &self.source_range
} }
pub fn type_info(&self) -> &TypeInfo {
self.type_info.as_ref().unwrap()
}
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.lhs.init_scopes(symbol_table, container_scope);
self.rhs.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.lhs.as_ref(), self.rhs.as_ref()] {
let (ns, mut ds) = expression.resolve_names_static(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_field_init(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.lhs.as_ref(), self.rhs.as_ref()] {
let (ns, mut ds) = expression.resolve_names_field_init(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.lhs.as_ref(), self.rhs.as_ref()] {
let (ns, mut ds) = expression.resolve_names_ctor(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for expression in [self.lhs.as_ref(), self.rhs.as_ref()] {
let (ns, mut ds) = expression.resolve_names_method(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
[
self.lhs
.check_field_initializer_names(symbol_table, class_symbol),
self.rhs
.check_field_initializer_names(symbol_table, class_symbol),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
[
self.lhs
.check_constructor_local_names(symbol_table, class_symbol),
self.rhs
.check_constructor_local_names(symbol_table, class_symbol),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
[
self.lhs
.check_method_local_names(symbol_table, class_symbol),
self.rhs
.check_method_local_names(symbol_table, class_symbol),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
[
self.lhs.check_static_fn_local_names(symbol_table),
self.rhs.check_static_fn_local_names(symbol_table),
]
.into_iter()
.flatten()
.collect()
}
fn resolve_op_result(
&self,
nodes_to_types: &NodesToTypes,
op_compatibility_check: impl Fn(&TypeInfo, &TypeInfo) -> bool,
get_op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo,
lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String,
) -> (TypeInfo, Diagnostics) {
let lhs_type_info = nodes_to_types.get(&self.lhs.node_id()).unwrap();
let rhs_type_info = nodes_to_types.get(&self.rhs.node_id()).unwrap();
if op_compatibility_check(lhs_type_info, rhs_type_info) {
let op_result = get_op_result(lhs_type_info, rhs_type_info);
(op_result, Diagnostics::new())
} else {
let mut diagnostics = Diagnostics::new();
diagnostics.push(
Diagnostic::new(
&lazy_diagnostic_message(lhs_type_info, rhs_type_info),
self.source_range.start(),
self.source_range.end(),
)
.with_error_code(BINARY_INCOMPATIBLE_TYPES),
);
(TypeInfo::PlaceholderError, diagnostics)
}
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_types = NodesToTypes::new();
{
let (nts, mut ds) = self.lhs.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
{
let (nts, mut ds) = self.rhs.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
{
let (result_type_info, mut ds) = match &self.op {
BinaryOperation::Multiply => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_multiply(rhs),
|lhs, rhs| lhs.multiply_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot multiply {} by {}", lhs, rhs),
),
BinaryOperation::Divide => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_divide(rhs),
|lhs, rhs| lhs.divide_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs),
),
BinaryOperation::Modulo => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_modulo(rhs),
|lhs, rhs| lhs.modulo_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs),
),
BinaryOperation::Add => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_add(rhs),
|lhs, rhs| lhs.add_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot add {} and {}", lhs, rhs),
),
BinaryOperation::Subtract => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_subtract(rhs),
|lhs, rhs| lhs.subtract_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot subtract {} from {}", rhs, lhs), // n.b. order
),
BinaryOperation::LeftShift => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_left_shift(rhs),
|lhs, rhs| lhs.left_shift_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot left shift {} by {}", lhs, rhs),
),
BinaryOperation::RightShift => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_right_shift(rhs),
|lhs, rhs| lhs.right_shift_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot right shift {} by {}", lhs, rhs),
),
BinaryOperation::BitwiseAnd => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_bitwise_and(rhs),
|lhs, rhs| lhs.bitwise_and_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot bitwise-and {} by {}", lhs, rhs),
),
BinaryOperation::BitwiseXor => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_bitwise_xor(rhs),
|lhs, rhs| lhs.bitwise_xor_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot bitwise-xor {} by {}", lhs, rhs),
),
BinaryOperation::BitwiseOr => self.resolve_op_result(
&nodes_to_types,
|lhs, rhs| lhs.can_bitwise_or(rhs),
|lhs, rhs| lhs.bitwise_or_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot bitwise-or {} by {}", lhs, rhs),
),
};
nodes_to_types.insert(self.node_id, result_type_info);
diagnostics.append(&mut ds);
}
(nodes_to_types, diagnostics)
}
fn check_op(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
check: impl Fn(&TypeInfo, &TypeInfo) -> bool,
op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo,
lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String,
) -> Result<(), Diagnostic> {
let lhs_type_info = self.lhs.type_info(symbol_table, types_table);
let rhs_type_info = self.rhs.type_info(symbol_table, types_table);
if check(lhs_type_info, rhs_type_info) {
self.type_info = Some(op_result(lhs_type_info, rhs_type_info));
Ok(())
} else {
let diagnostic = Diagnostic::new(
&lazy_diagnostic_message(lhs_type_info, rhs_type_info),
self.source_range.start(),
self.source_range.end(),
)
.with_primary_label_message("Incompatible types for addition.")
.with_reporter(file!(), line!())
.with_error_code(BINARY_INCOMPATIBLE_TYPES);
Err(diagnostic)
}
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
handle_diagnostics!(self.lhs.type_check(symbol_table, types_table), diagnostics);
handle_diagnostics!(self.rhs.type_check(symbol_table, types_table), diagnostics);
maybe_return_diagnostics!(diagnostics);
match &self.op {
BinaryOperation::Multiply => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_multiply(rhs),
|lhs, rhs| lhs.multiply_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot multiply {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::Divide => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_divide(rhs),
|lhs, rhs| lhs.divide_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs)
),
diagnostics
);
}
BinaryOperation::Modulo => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_modulo(rhs),
|lhs, rhs| lhs.modulo_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs)
),
diagnostics
);
}
BinaryOperation::Add => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_add(rhs),
|lhs, rhs| lhs.add_result(&rhs),
|lhs, rhs| format!("Incompatible types: cannot add {} to {}.", rhs, lhs)
),
diagnostics
);
}
BinaryOperation::Subtract => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_subtract(rhs),
|lhs, rhs| lhs.subtract_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot subtract {} from {}.",
rhs, lhs
)
),
diagnostics
)
}
BinaryOperation::LeftShift => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_left_shift(rhs),
|lhs, rhs| lhs.left_shift_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot left shift {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::RightShift => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_right_shift(rhs),
|lhs, rhs| lhs.right_shift_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot right shift {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::BitwiseAnd => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_bitwise_and(rhs),
|lhs, rhs| lhs.bitwise_and_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot bitwise and {} by {}",
lhs, rhs
)
),
diagnostics
);
}
BinaryOperation::BitwiseXor => handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_bitwise_xor(rhs),
|lhs, rhs| lhs.bitwise_xor_result(rhs),
|lhs, rhs| format!("Incompatible types: cannot bitwise xor {} by {}", lhs, rhs)
),
diagnostics
),
BinaryOperation::BitwiseOr => {
handle_diagnostic!(
self.check_op(
symbol_table,
types_table,
|lhs, rhs| lhs.can_bitwise_or(rhs),
|lhs, rhs| lhs.bitwise_or_result(rhs),
|lhs, rhs| format!(
"Incompatible types: cannot bitwise or {} by {}",
lhs, rhs
)
),
diagnostics
);
}
}
diagnostics_result!(diagnostics)
}
pub fn lower_to_ir_operation(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrOperation {
let lhs = self.lhs.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
let rhs = self.rhs.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
let ir_binary_operator = match &self.op {
BinaryOperation::Multiply => IrBinaryOperator::Multiply,
BinaryOperation::Divide => IrBinaryOperator::Divide,
BinaryOperation::Modulo => IrBinaryOperator::Modulo,
BinaryOperation::Add => IrBinaryOperator::Add,
BinaryOperation::Subtract => IrBinaryOperator::Subtract,
BinaryOperation::LeftShift => IrBinaryOperator::LeftShift,
BinaryOperation::RightShift => IrBinaryOperator::RightShift,
BinaryOperation::BitwiseAnd => IrBinaryOperator::BitwiseAnd,
BinaryOperation::BitwiseXor => IrBinaryOperator::BitwiseXor,
BinaryOperation::BitwiseOr => IrBinaryOperator::BitwiseOr,
};
IrOperation::Binary(IrBinaryOperation::new(lhs, rhs, ir_binary_operator))
}
#[deprecated]
pub fn to_ir_operation(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrOperation {
let lhs = self
.lhs
.to_ir_expression(builder, symbol_table, types_table)
.expect("Attempt to use a non-value expression in binary expression.");
let rhs = self
.rhs
.to_ir_expression(builder, symbol_table, types_table)
.expect("Attempt to use a non-value expression in binary expression.");
let ir_binary_operation = match self.op {
BinaryOperation::Multiply => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Multiply)
}
BinaryOperation::Divide => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Divide),
BinaryOperation::Modulo => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Modulo),
BinaryOperation::Add => IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Add),
BinaryOperation::Subtract => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::Subtract)
}
BinaryOperation::LeftShift => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::LeftShift)
}
BinaryOperation::RightShift => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::RightShift)
}
BinaryOperation::BitwiseAnd => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseAnd)
}
BinaryOperation::BitwiseXor => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseXor)
}
BinaryOperation::BitwiseOr => {
IrBinaryOperation::new(lhs, rhs, IrBinaryOperator::BitwiseOr)
}
};
IrOperation::Binary(ir_binary_operation)
}
#[deprecated]
pub fn to_ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrExpression {
let ir_operation = self.to_ir_operation(builder, symbol_table, types_table);
let t_var = todo!();
let as_rc = Rc::new(RefCell::new(t_var));
let ir_assign = IrAssign::new(todo!(), ir_operation);
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
IrExpression::Variable(todo!())
}
pub fn lower_to_ir_expression(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrExpression {
let ir_operation =
self.lower_to_ir_operation(builder, nodes_to_symbols, symbols_to_types, nodes_to_types);
let type_info = nodes_to_types.get(&self.node_id).unwrap();
let t_var = Rc::new(RefCell::new(todo!()));
let ir_assign = IrAssign::new(todo!(), ir_operation);
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
IrExpression::Variable(todo!())
}
} }

View File

@ -1,22 +1,6 @@
use crate::ast::NodeId;
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::fqn_util::fqn_parts_to_string;
use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::{
class_has_no_constructor, mismatched_types, receiver_not_callable, wrong_number_of_arguments,
};
use crate::ir::ir_call::IrCall;
use crate::ir::ir_expression::IrExpression;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::callable_symbol::CallableSymbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
pub struct Call { pub struct Call {
node_id: NodeId, node_id: NodeId,
@ -52,470 +36,6 @@ impl Call {
&self.arguments &self.arguments
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.callee.init_scopes(symbol_table, container_scope);
for argument in &mut self.arguments {
argument.init_scopes(symbol_table, container_scope);
}
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self.callee.resolve_names_static(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
for argument in &self.arguments {
let (ns, mut ds) = argument.resolve_names_static(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_field_init(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
.callee
.resolve_names_field_init(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
for argument in &self.arguments {
let (ns, mut ds) = argument.resolve_names_field_init(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
.callee
.resolve_names_ctor(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
for argument in &self.arguments {
let (ns, mut ds) = argument.resolve_names_ctor(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_symbols = NodesToSymbols::new();
{
let (ns, mut ds) = self
.callee
.resolve_names_method(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
for argument in &self.arguments {
let (ns, mut ds) = argument.resolve_names_method(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
(nodes_to_symbols, diagnostics)
}
#[deprecated]
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
diagnostics.append(
&mut self
.callee
.check_field_initializer_names(symbol_table, class_symbol),
);
for argument in &self.arguments {
diagnostics
.append(&mut argument.check_field_initializer_names(symbol_table, class_symbol))
}
diagnostics
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
for argument in &self.arguments {
diagnostics
.append(&mut argument.check_constructor_local_names(symbol_table, class_symbol))
}
diagnostics.append(
&mut self
.callee
.check_constructor_local_names(symbol_table, class_symbol),
);
diagnostics
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
for argument in &self.arguments {
diagnostics.append(&mut argument.check_method_local_names(symbol_table, class_symbol));
}
diagnostics.append(
&mut self
.callee
.check_method_local_names(symbol_table, class_symbol),
);
diagnostics
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
for argument in &self.arguments {
diagnostics.append(&mut argument.check_static_fn_local_names(symbol_table));
}
diagnostics.append(&mut self.callee.check_static_fn_local_names(symbol_table));
diagnostics
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_types = NodesToTypes::new();
{
let (nts, mut ds) = self
.callee
.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
for argument in &self.arguments {
let (nts, mut ds) = argument.resolve_types(nodes_to_symbols, symbols_to_types);
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
// get callee symbol and check that its callable
let callee_symbol = nodes_to_symbols.get(&self.callee.node_id()).unwrap();
let callable_symbol = match callee_symbol {
Symbol::Class(class_symbol) => match class_symbol.constructor_symbol_owned() {
None => {
diagnostics.push(class_has_no_constructor(
class_symbol.declared_name(),
self.callee.source_range(),
));
CallableSymbol::ErrorPlaceholder
}
Some(constructor_symbol) => CallableSymbol::Constructor(constructor_symbol),
},
Symbol::Function(function_symbol) => CallableSymbol::Function(function_symbol.clone()),
_ => {
diagnostics.push(receiver_not_callable(
symbols_to_types.get(&callee_symbol).unwrap(),
self.callee.source_range(),
));
CallableSymbol::ErrorPlaceholder
}
};
let parameter_symbols = callable_symbol.parameters();
// check args length
if parameter_symbols.len() != self.arguments().len() {
diagnostics.push(wrong_number_of_arguments(
self.source_range(),
parameter_symbols.len(),
self.arguments().len(),
));
}
// check arg types
for i in 0..parameter_symbols.len() {
let parameter_symbol = parameter_symbols[i].clone();
let argument = if i < self.arguments.len() {
&self.arguments[i]
} else {
continue;
};
let parameter_type_info = symbols_to_types
.get(&Symbol::Parameter(parameter_symbol))
.unwrap();
let argument_type_info = nodes_to_types.get(&argument.node_id()).unwrap();
if !parameter_type_info.is_assignable_from(argument_type_info) {
diagnostics.push(mismatched_types(
parameter_type_info,
argument_type_info,
argument.source_range(),
));
}
}
// TODO: insert self type (i.e., the return type of the call)
(nodes_to_types, diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.callee.as_mut().type_check(symbol_table, types_table)?;
let mut diagnostics: Vec<Diagnostic> = self
.arguments
.iter_mut()
.map(|argument| argument.type_check(symbol_table, types_table))
.filter_map(Result::err)
.flatten()
.collect();
// check that callee is callable
let callable_symbol = match self.callee.type_info(symbol_table, types_table) {
TypeInfo::Function(function_symbol) => {
CallableSymbol::Function(function_symbol.clone())
}
TypeInfo::Class(class_symbol) => match class_symbol.constructor_symbol_owned() {
None => {
diagnostics.push(class_has_no_constructor(
class_symbol.declared_name(),
self.callee.source_range(),
));
return Err(diagnostics);
}
Some(constructor_symbol) => CallableSymbol::Constructor(constructor_symbol),
},
_ => {
diagnostics.push(Diagnostic::new(
&format!(
"Receiver of type {} is not callable.",
self.callee.type_info(symbol_table, types_table)
),
self.callee.source_range().start(),
self.callee.source_range().end(),
));
return Err(diagnostics);
}
};
// check arguments length
let parameters = callable_symbol.parameters();
if parameters.len() != self.arguments.len() {
diagnostics.push(Diagnostic::new(
&format!(
"Wrong number of arguments; expected {} but found {}",
parameters.len(),
self.arguments.len()
),
self.source_range.start(),
self.source_range.end(),
));
}
if !diagnostics.is_empty() {
return Err(diagnostics);
}
// check argument types
for i in 0..parameters.len() {
let parameter = &parameters[i];
let argument = &self.arguments[i];
let parameter_type_info = types_table.parameter_types().get(parameter).unwrap();
let argument_type_info = argument.type_info(symbol_table, types_table);
if !parameter_type_info.is_assignable_from(argument_type_info) {
diagnostics.push(Diagnostic::new(
&format!(
"Mismatched types: expected {} but found {}",
parameter_type_info, argument_type_info
),
argument.source_range().start(),
argument.source_range().end(),
))
}
}
if diagnostics.is_empty() {
Ok(())
} else {
Err(diagnostics)
}
}
#[deprecated]
fn get_callee_symbol(&self, symbol_table: &SymbolTable) -> CallableSymbol {
match self.callee() {
Expression::Identifier(identifier) => {
let expressible_symbol = symbol_table
.find_expressible_symbol(identifier.scope_id(), identifier.name())
.unwrap();
match expressible_symbol {
ExpressibleSymbol::Function(function_symbol) => {
CallableSymbol::Function(function_symbol.clone())
}
ExpressibleSymbol::Class(class_symbol) => {
match class_symbol.constructor_symbol_owned() {
None => {
panic!("Attempt to get non-existent constructor symbol")
}
Some(constructor_symbol) => {
CallableSymbol::Constructor(constructor_symbol)
}
}
}
_ => panic!("Calling things other than functions not yet supported."),
}
}
_ => panic!("Calling things other than identifiers not yet supported."),
}
}
#[deprecated]
pub fn return_type_info<'a>(
&self,
symbol_table: &SymbolTable,
types_table: &'a TypesTable,
) -> &'a TypeInfo {
match self.get_callee_symbol(symbol_table) {
CallableSymbol::Function(function_symbol) => types_table
.function_return_types()
.get(&function_symbol)
.unwrap(),
CallableSymbol::Constructor(constructor_symbol) => types_table
.constructor_return_types()
.get(&constructor_symbol)
.unwrap(),
CallableSymbol::ErrorPlaceholder => unreachable!(),
}
}
pub fn lower_to_ir(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrCall {
let arguments = self
.arguments
.iter()
.map(|expression| {
expression.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
)
})
.collect::<Vec<_>>();
let callee_symbol = nodes_to_symbols.get(&self.callee().node_id()).unwrap();
let callable_symbol = match callee_symbol {
Symbol::Class(class_symbol) => match class_symbol.constructor_symbol_owned() {
None => panic!(),
Some(constructor_symbol) => CallableSymbol::Constructor(constructor_symbol),
},
Symbol::Function(function_symbol) => CallableSymbol::Function(function_symbol.clone()),
_ => panic!(),
};
match callable_symbol {
CallableSymbol::Function(function_symbol) => IrCall::new(
fqn_parts_to_string(function_symbol.fqn_parts()),
arguments,
function_symbol.is_extern(),
),
CallableSymbol::Constructor(constructor_symbol) => IrCall::new(
fqn_parts_to_string(constructor_symbol.fqn_parts()),
arguments,
constructor_symbol.is_extern(),
),
CallableSymbol::ErrorPlaceholder => unreachable!(),
}
}
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrCall {
let arguments: Vec<IrExpression> = self
.arguments
.iter()
.map(|argument| argument.to_ir_expression(builder, symbol_table, types_table))
.inspect(|expression| {
if expression.is_none() {
panic!("Attempt to pass non-expression")
}
})
.map(Option::unwrap)
.collect();
let callable_symbol = self.get_callee_symbol(symbol_table);
match callable_symbol {
CallableSymbol::Function(function_symbol) => IrCall::new(
fqn_parts_to_string(function_symbol.fqn_parts()),
arguments,
function_symbol.is_extern(),
),
CallableSymbol::Constructor(constructor_symbol) => IrCall::new(
fqn_parts_to_string(constructor_symbol.fqn_parts()),
arguments,
false,
),
CallableSymbol::ErrorPlaceholder => unreachable!(),
}
}
pub fn source_range(&self) -> &SourceRange { pub fn source_range(&self) -> &SourceRange {
&self.source_range &self.source_range
} }

View File

@ -1,30 +1,9 @@
use crate::ast::assign_statement::AssignStatement; use crate::ast::NodeId;
use crate::ast::constructor::Constructor; use crate::ast::constructor::Constructor;
use crate::ast::expression::Expression;
use crate::ast::field::Field; use crate::ast::field::Field;
use crate::ast::fqn_context::FqnContext;
use crate::ast::fqn_util::fqn_parts_to_string;
use crate::ast::function::Function; use crate::ast::function::Function;
use crate::ast::generic_parameter::GenericParameter; use crate::ast::generic_parameter::GenericParameter;
use crate::ast::helpers::{
collect_diagnostics_mut, collect_diagnostics_single, insert_resolved_names_into,
resolve_ctor_name,
};
use crate::ast::statement::Statement;
use crate::ast::{FunctionReturnTypes, NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT};
use crate::ir::ir_class::{IrClass, IrField};
use crate::ir::ir_function::IrFunction;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::constructor_symbol::ConstructorSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics, ok_or_err_diagnostics};
use std::collections::HashSet;
use std::rc::Rc; use std::rc::Rc;
pub struct Class { pub struct Class {
@ -35,9 +14,6 @@ pub struct Class {
constructor: Option<Constructor>, constructor: Option<Constructor>,
fields: Vec<Field>, fields: Vec<Field>,
functions: Vec<Function>, functions: Vec<Function>,
scope_id: Option<usize>,
self_class_scope_id: Option<usize>,
self_class_body_scope_id: Option<usize>,
} }
impl Class { impl Class {
@ -58,523 +34,6 @@ impl Class {
constructor, constructor,
fields, fields,
functions, functions,
scope_id: None,
self_class_scope_id: None,
self_class_body_scope_id: None,
} }
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
let class_scope_id =
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
self.self_class_scope_id = Some(class_scope_id);
for generic_parameter in &mut self.generic_parameters {
generic_parameter.init_scopes(symbol_table, class_scope_id);
}
let class_body_scope_id = symbol_table
.push_class_body_scope(&format!("class_body_scope({})", self.declared_name));
self.self_class_body_scope_id = Some(class_body_scope_id);
for field in &mut self.fields {
field.init_scopes(symbol_table, class_body_scope_id);
}
if let Some(constructor) = &mut self.constructor {
constructor.init_scopes(symbol_table, class_body_scope_id);
}
for function in &mut self.functions {
function.init_scopes(symbol_table, class_body_scope_id);
}
symbol_table.pop_scope();
symbol_table.pop_scope();
}
pub fn declared_symbols(&self, fqn_context: &FqnContext) -> Vec<Symbol> {
let mut all_symbols: Vec<Symbol> = Vec::new();
let mut generic_parameter_symbols = Vec::new();
for generic_parameter in &self.generic_parameters {
let symbol = Rc::new(generic_parameter.make_symbol());
all_symbols.push(Symbol::GenericParameter(symbol.clone()));
generic_parameter_symbols.push(symbol);
}
let mut field_symbols = Vec::new();
for (field_index, field) in self.fields.iter().enumerate() {
let symbol = Rc::new(field.make_symbol(field_index));
all_symbols.push(Symbol::Field(symbol.clone()));
field_symbols.push(symbol);
}
let class_body_fqn_context = fqn_context.with_part(&self.declared_name);
let constructor_symbol = if let Some(constructor) = &self.constructor {
let (constructor_symbol, mut symbols) =
constructor.make_symbols(&class_body_fqn_context);
all_symbols.append(&mut symbols);
constructor_symbol
} else {
Rc::new(ConstructorSymbol::new(
&self.declared_name_source_range,
resolve_ctor_name(&class_body_fqn_context),
false,
true,
self.self_class_body_scope_id.unwrap(),
vec![],
))
};
all_symbols.push(Symbol::Constructor(constructor_symbol.clone()));
let mut function_symbols = Vec::new();
for function in &self.functions {
let (function_symbol, mut symbols) =
function.declared_symbols(&class_body_fqn_context, true);
all_symbols.append(&mut symbols);
function_symbols.push(function_symbol);
}
let class_symbol = Rc::new(ClassSymbol::new(
&self.declared_name,
Some(self.declared_name_source_range.clone()),
fqn_context.resolve(&self.declared_name), // not class body!
false,
self.scope_id.unwrap(),
generic_parameter_symbols,
Some(constructor_symbol),
field_symbols,
function_symbols,
));
all_symbols.push(Symbol::Class(class_symbol.clone()));
all_symbols
}
pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for generic_parameter in &self.generic_parameters {
let (ns, mut ds) = generic_parameter.resolve_names(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
let self_class_symbol = self.get_class_symbol_owned(symbol_table);
let mut initialized_fields = HashSet::new();
for field in &self.fields {
let (ns, mut ds) = field.resolve_names(symbol_table, &self_class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
initialized_fields.insert(field.declared_name_owned());
}
if let Some(constructor) = &self.constructor {
let (ns, mut ds) = constructor.resolve_names(
symbol_table,
self_class_symbol.as_ref(),
&mut initialized_fields,
);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
for generic_parameter in &self.generic_parameters {
diagnostics.append(&mut generic_parameter.check_names(symbol_table));
}
for field in &self.fields {
diagnostics.append(&mut field.check_names(symbol_table));
}
if let Some(constructor) = &self.constructor {
diagnostics.append(&mut constructor.check_names(symbol_table));
}
for function in &self.functions {
diagnostics.append(&mut function.check_names(symbol_table));
}
diagnostics
}
fn get_self_class_symbol<'a>(&self, symbol_table: &'a SymbolTable) -> &'a ClassSymbol {
symbol_table
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
.unwrap()
.as_ref()
}
fn get_class_symbol_owned(&self, symbol_table: &SymbolTable) -> Rc<ClassSymbol> {
symbol_table
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
.cloned()
.unwrap()
}
pub fn check_field_initializer_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let class_symbol = self.get_class_symbol_owned(symbol_table);
self.fields
.iter()
.flat_map(|field| field.check_field_initializer_names(symbol_table, &class_symbol))
.collect()
}
#[deprecated]
pub fn analyze_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let class_symbol = self.get_class_symbol_owned(symbol_table);
let mut diagnostics: Vec<Diagnostic> = Vec::new();
if let Some(constructor) = &self.constructor {
diagnostics.append(&mut constructor.analyze_local_names(symbol_table, &class_symbol));
}
for function in &self.functions {
diagnostics
.append(&mut function.analyze_method_local_names(symbol_table, &class_symbol));
}
diagnostics
}
#[deprecated]
pub fn gather_types(
&self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
// class type
let class_symbol = self.get_class_symbol_owned(symbol_table);
types_table
.class_types_mut()
.insert(class_symbol.clone(), TypeInfo::Class(class_symbol.clone()));
// constructor return type
// this works for both declared and default constructors
let constructor_symbol = symbol_table
.get_constructor_symbol_owned(self.self_class_body_scope_id.unwrap())
.unwrap();
types_table
.constructor_return_types_mut()
.insert(constructor_symbol, TypeInfo::Class(class_symbol));
let mut diagnostics = Vec::new();
// generic params
for generic_parameter in &self.generic_parameters {
handle_diagnostics!(
generic_parameter.gather_types(symbol_table, types_table),
diagnostics
);
}
// field types
for field in &self.fields {
handle_diagnostics!(field.gather_types(symbol_table, types_table), diagnostics);
}
// now the constructor (parameters, etc.)
if let Some(constructor) = &self.constructor {
constructor.gather_types_into(symbol_table, types_table);
}
// function return types
for function in &self.functions {
function.gather_types(symbol_table, types_table);
}
diagnostics_result!(diagnostics)
}
fn type_check_generics(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
collect_diagnostics_mut(&mut self.generic_parameters, |gp| {
gp.type_check(symbol_table, types_table)
})
}
fn type_check_fields(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
collect_diagnostics_mut(&mut self.fields, |f| {
f.type_check(symbol_table, types_table)
})
}
fn type_check_constructor(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
if let Some(constructor) = &mut self.constructor {
constructor.type_check(symbol_table, types_table)?;
}
Ok(())
}
fn type_check_functions(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
collect_diagnostics_mut(&mut self.functions, |f| {
f.type_check(symbol_table, types_table)
})
}
/// Returns all field names with declared initializers.
fn field_names_with_initializers(&self) -> HashSet<&str> {
let mut set: HashSet<&str> = HashSet::new();
for field in &self.fields {
if field.initializer().is_some() {
set.insert(field.declared_name());
}
}
set
}
/// If the destination of the given [AssignStatement] matches a field, returns an
/// `Ok(Some(field_name))` only if the field is not already in the `fields_already_init` set,
/// AND, if the field is immutable, the field is not initialized more than once in the
/// constructor. Otherwise, returns an `Err(Diagnostic)`.
fn check_ctor_assign_statement<'a>(
&self,
assign_statement: &'a AssignStatement,
fields_already_init: &HashSet<&&str>,
class_symbol: &ClassSymbol,
) -> Result<Option<&'a str>, Diagnostic> {
match assign_statement.destination() {
Expression::Identifier(identifier) => {
// find matching field symbol, if there is one
if let Some(field_symbol) = class_symbol.fields().get(identifier.name()) {
// check that we don't init more than once IF field is immutable
if fields_already_init.contains(&identifier.name()) && !field_symbol.is_mut() {
let diagnostic = Diagnostic::new(
&format!("Immutable field {} cannot be initialized more than once in constructor.", identifier.name()),
identifier.source_range().start(),
identifier.source_range().end(),
).with_reporter(file!(), line!())
.with_error_code(FIELD_MULTIPLE_INIT);
Err(diagnostic)
} else {
Ok(Some(identifier.name()))
}
} else {
Ok(None)
}
}
_ => panic!("Found a non-L Value destination"),
}
}
/// Returns an `Ok(HashSet<&str>)` containing the names of all fields initialized in the
/// constructor, provided that the following are true:
///
/// - The field is not initialized more than once in the constructor
/// - The field is not also initialized with a declared initializer.
///
/// If the above are not met, returns `Err(diagnostics)`.
fn get_fields_init_in_ctor<'a>(
&self,
fields_with_declared_initializers: &HashSet<&str>,
symbol_table: &SymbolTable,
) -> Result<HashSet<&str>, Vec<Diagnostic>> {
let mut constructor_inits: HashSet<&str> = HashSet::new();
let mut diagnostics: Vec<Diagnostic> = vec![];
if let Some(constructor) = &self.constructor {
let class_symbol = symbol_table
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
for statement in constructor.statements() {
match statement {
Statement::Assign(assign_statement) => {
let fields_init_so_far = constructor_inits
.union(fields_with_declared_initializers)
.collect::<HashSet<_>>();
match self.check_ctor_assign_statement(
assign_statement,
&fields_init_so_far,
&class_symbol,
) {
Ok(maybe_init_field) => match maybe_init_field {
None => {}
Some(init_field) => {
constructor_inits.insert(init_field);
}
},
Err(diagnostic) => {
diagnostics.push(diagnostic);
}
}
}
_ => {}
}
}
}
ok_or_err_diagnostics!(constructor_inits, diagnostics)
}
/// Checks that all declared fields in this `Class` are present in the `all_inits` set. If so,
/// returns `Ok`, else `Err`.
fn check_all_fields_in_init_set(
&self,
all_inits: &HashSet<&&str>,
) -> Result<(), Vec<Diagnostic>> {
collect_diagnostics_single(&self.fields, |field| {
if all_inits.contains(&field.declared_name()) {
Ok(())
} else {
Err(Diagnostic::new(
&format!("Field {} is not initialized.", field.declared_name()),
field.declared_name_source_range().start(),
field.declared_name_source_range().end(),
)
.with_primary_label_message("Must be initialized in declaration or constructor.")
.with_reporter(file!(), line!())
.with_error_code(FIELD_UNINIT))
}
})
}
/// Checks that all fields are initialized, either at their declaration or in the constructor.
/// Immutable fields may be only initialized once, either at their declaration or once in the
/// constructor. Mutable fields may be initialized either at their declaration, or at least once
/// in the constructor.
fn check_field_initialization(
&self,
symbol_table: &SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
// We need to determine if fields are initialized or not (the latter is an error).
// First phase: check all fields, then check constructor, leaving pending those things that
// are fields <- initialized by constructor. Then circle back to fields and check all are
// initialized
let field_names_with_initializers = self.field_names_with_initializers();
let field_names_init_in_constructor =
self.get_fields_init_in_ctor(&field_names_with_initializers, symbol_table)?;
let combined = field_names_with_initializers
.union(&field_names_init_in_constructor)
.collect::<HashSet<_>>();
// check that all fields are present in the hash set
self.check_all_fields_in_init_set(&combined)?;
Ok(())
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.type_check_generics(symbol_table, types_table)?;
self.type_check_fields(symbol_table, types_table)?;
self.type_check_constructor(symbol_table, types_table)?;
self.type_check_functions(symbol_table, types_table)?;
self.check_field_initialization(symbol_table)?;
Ok(())
}
#[deprecated]
pub fn to_ir(
&self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> (IrClass, Vec<IrFunction>) {
let self_class_symbol = symbol_table
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
let mut ir_functions: Vec<IrFunction> = vec![];
if let Some(constructor) = &self.constructor {
ir_functions.push(constructor.to_ir(
self_class_symbol,
&self.fields,
symbol_table,
types_table,
))
}
for function in &self.functions {
ir_functions.push(function.to_ir(symbol_table, types_table, Some(self_class_symbol)));
}
let ir_class = IrClass::new(
self_class_symbol.declared_name_owned(),
fqn_parts_to_string(self_class_symbol.fqn_parts()).into(),
self.fields
.iter()
.map(|field| {
let field_symbol = symbol_table
.get_field_symbol_owned(field.scope_id(), field.declared_name())
.unwrap();
let field_type = types_table.field_types().get(&field_symbol).unwrap();
IrField::new(
field.declared_name().into(),
field_symbol.field_index(),
field_type.clone(),
)
})
.collect(),
);
(ir_class, ir_functions)
}
pub fn lower_to_ir(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> (IrClass, Vec<IrFunction>) {
let mut ir_functions = Vec::new();
let self_class_symbol = nodes_to_symbols
.get(&self.node_id)
.unwrap()
.unwrap_class_symbol();
if let Some(constructor) = &self.constructor {
ir_functions.push(constructor.lower_to_ir(
self_class_symbol,
&self.fields,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
));
}
for function in &self.functions {
ir_functions.push(function.lower_to_ir_static(
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
));
}
let ir_class = IrClass::new(
self_class_symbol.declared_name_owned(),
fqn_parts_to_string(self_class_symbol.fqn_parts()).into(),
self.fields
.iter()
.map(|field| field.lower_to_ir_field(nodes_to_symbols, symbols_to_types))
.collect(),
);
(ir_class, ir_functions)
}
} }

View File

@ -1,20 +1,7 @@
use crate::FileId;
use crate::ast::class::Class; use crate::ast::class::Class;
use crate::ast::extern_function::ExternFunction; use crate::ast::extern_function::ExternFunction;
use crate::ast::fqn_context::FqnContext;
use crate::ast::function::Function; use crate::ast::function::Function;
use crate::ast::helpers::{
collect_diagnostics_into_mut, insert_declared_types_into, insert_resolved_types_into,
};
use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::compile_pipeline::FileId;
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_class::IrClass;
use crate::ir::ir_function::IrFunction;
use crate::symbol::Symbol;
use crate::symbol_table::SymbolTable;
use crate::symbol_table::util::try_insert_symbols_into;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics};
pub struct CompilationUnit { pub struct CompilationUnit {
file_id: Option<FileId>, file_id: Option<FileId>,
@ -49,258 +36,4 @@ impl CompilationUnit {
pub fn classes(&self) -> &[Class] { pub fn classes(&self) -> &[Class] {
&self.classes &self.classes
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable) {
let compilation_unit_scope = symbol_table.push_module_scope("compilation_unit_scope");
for class in &mut self.classes {
class.init_scopes(symbol_table, compilation_unit_scope);
}
for function in &mut self.functions {
function.init_scopes(symbol_table, compilation_unit_scope);
}
for extern_function in &mut self.extern_functions {
extern_function.init_scopes(symbol_table, compilation_unit_scope);
}
symbol_table.pop_scope();
}
pub fn declared_symbols(&self) -> Vec<Symbol> {
let fqn_context = FqnContext::new();
[
self.classes
.iter()
.flat_map(|class| class.declared_symbols(&fqn_context))
.collect::<Vec<_>>(),
self.extern_functions
.iter()
.flat_map(|function| function.declared_symbols(&fqn_context).1)
.collect(),
self.functions
.iter()
.flat_map(|function| function.declared_symbols(&fqn_context, false).1)
.collect(),
]
.into_iter()
.flatten()
.collect()
}
#[deprecated]
pub fn gather_symbols_into(
&self,
symbol_table: &mut SymbolTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics = vec![];
let fqn_context = FqnContext::new();
for class in &self.classes {
handle_diagnostics!(
try_insert_symbols_into(class.declared_symbols(&fqn_context), symbol_table),
diagnostics
);
}
for function in &self.functions {
let (_, symbols) = function.declared_symbols(&fqn_context, false);
handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics);
}
for extern_function in &self.extern_functions {
let (_, symbols) = extern_function.declared_symbols(&fqn_context);
handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics);
}
diagnostics_result!(diagnostics)
}
pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for function in &self.functions {
let (ns, mut ds) = function.resolve_names_static(symbol_table);
for (node_id, symbol) in ns.into_iter() {
names_table.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
for extern_function in &self.extern_functions {
let (ns, mut ds) = extern_function.resolve_names_static(symbol_table);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
for class in &self.classes {
let (ns, mut ds) = class.resolve_names(symbol_table);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &mut SymbolTable) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics = vec![];
for class in &self.classes {
diagnostics.append(&mut class.check_names(symbol_table));
diagnostics.append(&mut class.check_field_initializer_names(symbol_table));
diagnostics.append(&mut class.analyze_local_names(symbol_table));
}
for function in &self.functions {
diagnostics.append(&mut function.check_names(symbol_table));
diagnostics.append(&mut function.analyze_static_fn_local_names(symbol_table));
}
for extern_function in &self.extern_functions {
diagnostics.append(&mut extern_function.check_names(symbol_table));
}
diagnostics_result!(diagnostics)
}
/// Associate each declared symbol with a TypeInfo.
pub fn declared_types(
&self,
nodes_to_symbols: &NodesToSymbols,
) -> (SymbolsToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut symbols_to_types = SymbolsToTypes::new();
for function in &self.functions {
let (sts, mut ds) = function.declared_types(nodes_to_symbols);
insert_declared_types_into(sts, &mut symbols_to_types);
diagnostics.append(&mut ds);
}
for extern_function in &self.extern_functions {
let (sts, mut ds) = extern_function.declared_types(nodes_to_symbols);
insert_declared_types_into(sts, &mut symbols_to_types);
diagnostics.append(&mut ds);
}
(symbols_to_types, diagnostics)
}
/// Resolve types of all nodes that have an implicit (perhaps not declared) type, checking that
/// things are assignable, etc., along the way.
pub fn resolve_types(
&self,
names_table: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (SymbolsToTypes, NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut resolved_types = NodesToTypes::new();
let mut symbols_to_types = symbols_to_types.clone();
for function in &self.functions {
let (sts, nts, mut ds) = function.resolve_types(names_table, &symbols_to_types);
insert_declared_types_into(sts, &mut symbols_to_types);
insert_resolved_types_into(nts, &mut resolved_types);
diagnostics.append(&mut ds);
}
(symbols_to_types, resolved_types, diagnostics)
}
#[deprecated]
pub fn gather_types_into(
&self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics = Vec::new();
for class in &self.classes {
handle_diagnostics!(class.gather_types(symbol_table, types_table), diagnostics);
}
for function in &self.functions {
function.gather_types(symbol_table, types_table);
}
for extern_function in &self.extern_functions {
extern_function.gather_types(symbol_table, types_table);
}
diagnostics_result!(diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
collect_diagnostics_into_mut(
&mut self.functions,
|f| f.type_check(symbol_table, types_table),
&mut diagnostics,
);
collect_diagnostics_into_mut(
&mut self.extern_functions,
|ef| ef.type_check(symbol_table, types_table),
&mut diagnostics,
);
collect_diagnostics_into_mut(
&mut self.classes,
|c| c.type_check(symbol_table, types_table),
&mut diagnostics,
);
diagnostics_result!(diagnostics)
}
pub fn lower_to_ir(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> (Vec<IrClass>, Vec<IrFunction>) {
let mut ir_classes = Vec::new();
let mut ir_functions = Vec::new();
for function in &self.functions {
ir_functions.push(function.lower_to_ir_static(
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
));
}
for class in &self.classes {
let (ir_class, mut class_ir_functions) =
class.lower_to_ir(nodes_to_symbols, symbols_to_types, nodes_to_types);
ir_classes.push(ir_class);
ir_functions.append(&mut class_ir_functions);
}
(ir_classes, ir_functions)
}
#[deprecated]
pub fn to_ir(
&self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> (Vec<IrClass>, Vec<IrFunction>) {
let mut functions: Vec<IrFunction> = vec![];
let mut classes: Vec<IrClass> = vec![];
self.functions
.iter()
.map(|f| f.to_ir(symbol_table, types_table, None))
.for_each(|f| functions.push(f));
for class in &self.classes {
let (class, mut class_functions) = class.to_ir(symbol_table, types_table);
functions.append(&mut class_functions);
classes.push(class);
}
(classes, functions)
}
} }

View File

@ -1,37 +1,7 @@
use crate::ast::field::Field; use crate::ast::NodeId;
use crate::ast::fqn_context::FqnContext;
use crate::ast::fqn_util::fqn_parts_to_string;
use crate::ast::helpers::{
collect_parameter_symbols_into, insert_resolved_names_into, resolve_ctor_name,
};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::parameter::Parameter; use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement; use crate::ast::statement::Statement;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_allocate::IrAllocate;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_function::IrFunction;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_return::IrReturn;
use crate::ir::ir_set_field::IrSetField;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::constructor_symbol::ConstructorSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::collections::HashSet;
use std::ops::Neg;
use std::rc::Rc;
pub struct Constructor { pub struct Constructor {
node_id: NodeId, node_id: NodeId,
@ -63,375 +33,4 @@ impl Constructor {
pub fn statements(&self) -> &[Statement] { pub fn statements(&self) -> &[Statement] {
&self.statements &self.statements
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
let function_scope = symbol_table.push_function_scope("constructor_scope");
for parameter in &mut self.parameters {
parameter.init_scopes(symbol_table, function_scope);
}
let body_scope = symbol_table.push_block_scope("body_scope");
for statement in &mut self.statements {
statement.init_scopes(symbol_table, body_scope);
}
symbol_table.pop_scope();
symbol_table.pop_scope();
}
pub fn make_symbols(&self, fqn_context: &FqnContext) -> (Rc<ConstructorSymbol>, Vec<Symbol>) {
let mut all_symbols: Vec<Symbol> = Vec::new();
let mut parameter_symbols = Vec::new();
collect_parameter_symbols_into(&self.parameters, &mut all_symbols, &mut parameter_symbols);
let constructor_symbol = Rc::new(ConstructorSymbol::new(
&self.ctor_keyword_source_range,
resolve_ctor_name(fqn_context),
false,
false,
self.scope_id.unwrap(),
parameter_symbols,
));
all_symbols.push(Symbol::Constructor(constructor_symbol.clone()));
(constructor_symbol, all_symbols)
}
pub fn resolve_names(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for parameter in &self.parameters {
let (ns, mut ds) = parameter.resolve_names(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
for statement in &self.statements {
let (ns, mut ds) =
statement.resolve_names_ctor(symbol_table, self_class_symbol, initialized_fields);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
for parameter in &self.parameters {
diagnostics.append(&mut parameter.check_names(symbol_table));
}
diagnostics
}
#[deprecated]
pub fn analyze_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.statements
.iter()
.flat_map(|s| s.analyze_constructor_local_names(symbol_table, class_symbol))
.collect()
}
#[deprecated]
pub fn gather_types_into(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) {
for parameter in &self.parameters {
parameter.gather_types_into(symbol_table, types_table);
}
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let parameters_diagnostics: Vec<Diagnostic> = self
.parameters
.iter_mut()
.map(|param| param.type_check(symbol_table, types_table))
.filter_map(Result::err)
.flatten()
.collect();
if !parameters_diagnostics.is_empty() {
return Err(parameters_diagnostics);
}
let statements_diagnostics: Vec<Diagnostic> = self
.statements
.iter_mut()
.map(|statement| statement.type_check(symbol_table, types_table, None))
.filter_map(Result::err)
.flatten()
.collect();
if statements_diagnostics.is_empty() {
Ok(())
} else {
Err(statements_diagnostics)
}
}
#[deprecated]
pub fn to_ir(
&self,
class_symbol: &Rc<ClassSymbol>,
fields: &[Field],
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrFunction {
let mut ir_builder = IrBuilder::new();
let parameters_count = self.parameters.len();
let ir_parameters = self
.parameters
.iter()
.enumerate()
.map(|(i, parameter)| {
let parameter_symbol = symbol_table
.get_parameter_symbol_owned(parameter.scope_id(), parameter.declared_name())
.unwrap();
let parameter_type = types_table
.parameter_types()
.get(&parameter_symbol)
.unwrap();
let offset = (parameters_count as isize).neg() + i as isize;
let ir_parameter = Rc::new(IrParameter::new(
parameter_symbol.declared_name(),
todo!(),
offset,
));
// make sure to save ir_parameter to symbol so others can access it
ir_builder.push_parameter(&parameter_symbol, ir_parameter.clone());
ir_parameter
})
.collect::<Vec<_>>();
let entry_block_id = ir_builder.new_block();
// first, allocate the object into a t var
let alloc_assign_destination = todo!();
let self_variable = Rc::new(RefCell::new(alloc_assign_destination));
// save self variable so statements can assign stuff to self's fields
ir_builder.set_self_parameter_or_variable(IrParameterOrVariable::Variable(todo!()));
let alloc_assign = IrAssign::new(
todo!(),
IrOperation::Allocate(IrAllocate::new(class_symbol.declared_name_owned())),
);
ir_builder
.current_block_mut()
.add_statement(IrStatement::Assign(alloc_assign));
// next, initialize fields that have an initializer in their declaration
for field in fields {
if let Some(initializer) = field.initializer() {
let field_symbol = symbol_table
.get_field_symbol_owned(field.scope_id(), field.declared_name())
.unwrap();
let field_type = types_table.field_types().get(&field_symbol).unwrap();
// get a mut ref to the field
let ir_get_field_ref_mut = IrGetFieldRefMut::new(
IrParameterOrVariable::Variable(todo!()),
field_symbol.field_index(),
);
let field_mut_ref_variable_name: Rc<str> = ir_builder.new_t_var().into();
let field_mut_ref_variable = Rc::new(RefCell::new(todo!()));
let field_mut_ref_assign =
IrAssign::new(todo!(), IrOperation::GetFieldRefMut(ir_get_field_ref_mut));
ir_builder
.current_block_mut()
.add_statement(IrStatement::Assign(field_mut_ref_assign));
// save the mut ref to the builder for other uses if needed
ir_builder
.field_mut_pointer_variables_mut()
.insert(field.declared_name_owned(), field_mut_ref_variable); // n.b. field name, not t var name
// now write the initializer result to the field
let field_mut_ref_variable = ir_builder
.field_mut_pointer_variables()
.get(field.declared_name())
.unwrap()
.clone();
let ir_expression = initializer
.to_ir_expression(&mut ir_builder, symbol_table, types_table)
.unwrap();
let ir_set_field = IrSetField::new(
todo!(), // dumb that we clone it and then ref it
ir_expression,
);
ir_builder
.current_block_mut()
.add_statement(IrStatement::SetField(ir_set_field));
}
}
// do "declared" statements of constructor
for statement in &self.statements {
statement.to_ir(&mut ir_builder, symbol_table, types_table, false);
}
// return complete self object
let ir_return_statement =
IrStatement::Return(IrReturn::new(Some(IrExpression::Variable(todo!()))));
ir_builder
.current_block_mut()
.add_statement(ir_return_statement);
ir_builder.finish_block();
let entry_block = ir_builder.get_block(entry_block_id);
let constructor_symbol = symbol_table
.get_constructor_symbol(self.scope_id.unwrap())
.unwrap();
todo!()
}
pub fn lower_to_ir(
&self,
class_symbol: &Rc<ClassSymbol>,
fields: &[Field],
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrFunction {
let mut ir_builder = IrBuilder::new();
// gather ir_parameters
let mut ir_parameters = Vec::new();
let base_offset = (self.parameters.len() as isize).neg();
for (i, parameter) in self.parameters.iter().enumerate() {
let symbol = nodes_to_symbols.get(&parameter.node_id()).unwrap();
let parameter_type = symbols_to_types.get(symbol).unwrap();
let offset = base_offset + i as isize;
let ir_parameter = Rc::new(IrParameter::new(symbol.declared_name(), todo!(), offset));
// save in builder
ir_builder.push_parameter(symbol.unwrap_parameter_symbol(), ir_parameter.clone());
// push for saving to IrFunction
ir_parameters.push(ir_parameter);
}
// entry-block
let entry_block_id = ir_builder.new_block();
// PART 1: Make self object
let self_variable = Rc::new(RefCell::new(todo!()));
//
// // save self variable in builder
// ir_builder
// .set_self_parameter_or_variable(IrParameterOrVariable::Variable(self_variable.clone()));
//
// // allocate the self object
// let ir_assign = IrAssign::new(
// self_variable.clone(),
// IrOperation::Allocate(IrAllocate::new(class_symbol.declared_name_owned())),
// );
// ir_builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(ir_assign));
//
// // PART 2: Initialize fields that are initialized OUTSIDE the constructor
// for field in fields {
// if let Some(initializer) = field.initializer() {
// let symbol = nodes_to_symbols.get(&field.node_id()).unwrap();
// let field_type = symbols_to_types.get(symbol).unwrap();
// let field_symbol = symbol.unwrap_field_symbol();
//
// // 1. Get a mut ref to the field
// // mut t_var: Type = &mut self.x
// let ir_get_field_ref_mut = IrGetFieldRefMut::new(
// IrParameterOrVariable::Variable(self_variable.clone()),
// field_symbol.field_index(),
// );
// let field_ref_mut_ir_variable = Rc::new(RefCell::new(IrVariable::new_vr(
// ir_builder.new_t_var().into(),
// ir_builder.current_block().id(),
// field_type,
// )));
// let ir_assign = IrAssign::new(
// field_ref_mut_ir_variable.clone(),
// IrOperation::GetFieldRefMut(ir_get_field_ref_mut),
// );
// ir_builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(ir_assign));
//
// // save the mut ref for later uses if needed
// ir_builder.field_mut_pointer_variables_mut().insert(
// field.declared_name_owned(),
// field_ref_mut_ir_variable.clone(),
// );
//
// // 2. Evaluate initializer and save result to mut field ref
// let ir_expression = initializer.lower_to_ir_expression(
// &mut ir_builder,
// nodes_to_symbols,
// symbols_to_types,
// nodes_to_types,
// );
// let ir_set_field = IrSetField::new(&field_ref_mut_ir_variable, ir_expression);
// ir_builder
// .current_block_mut()
// .add_statement(IrStatement::SetField(ir_set_field));
// }
// }
//
// // PART 3. Constructor statements
// for statement in &self.statements {
// statement.lower_to_ir(
// &mut ir_builder,
// nodes_to_symbols,
// symbols_to_types,
// nodes_to_types,
// false,
// );
// }
//
// // PART 4. Return finished self object
// let ir_return_statement = IrStatement::Return(IrReturn::new(Some(IrExpression::Variable(
// self_variable.clone(),
// ))));
// ir_builder
// .current_block_mut()
// .add_statement(ir_return_statement);
//
// // Finish up the builder and return IrFunction
// ir_builder.finish_block();
// let entry_block = ir_builder.get_block(entry_block_id);
//
// let constructor_symbol = nodes_to_symbols
// .get(&self.node_id)
// .unwrap()
// .unwrap_constructor_symbol();
// IrFunction::new(
// fqn_parts_to_string(constructor_symbol.fqn_parts()),
// ir_parameters,
// &TypeInfo::Class(class_symbol.clone()), // TODO
// entry_block.clone(),
// )
todo!()
}
} }

View File

@ -1,25 +1,12 @@
use crate::ast::NodeId;
use crate::ast::binary_expression::BinaryExpression; use crate::ast::binary_expression::BinaryExpression;
use crate::ast::call::Call; use crate::ast::call::Call;
use crate::ast::double_literal::DoubleLiteral; use crate::ast::double_literal::DoubleLiteral;
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::negative_expression::NegativeExpression; use crate::ast::negative_expression::NegativeExpression;
use crate::ast::string_literal::StringLiteral; use crate::ast::string_literal::StringLiteral;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
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_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::rc::Rc;
pub enum Expression { pub enum Expression {
Binary(BinaryExpression), Binary(BinaryExpression),
@ -44,321 +31,6 @@ impl Expression {
} }
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.init_scopes(symbol_table, container_scope);
}
Expression::Negative(negative_expression) => {
negative_expression.init_scopes(symbol_table, container_scope);
}
Expression::Call(call) => {
call.init_scopes(symbol_table, container_scope);
}
Expression::Identifier(identifier) => {
identifier.init_scope_id(container_scope);
}
_ => {}
}
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_static(symbol_table)
}
Expression::Negative(negative_expression) => {
negative_expression.resolve_names_static(symbol_table)
}
Expression::Call(call) => call.resolve_names_static(symbol_table),
Expression::Identifier(identifier) => identifier.resolve_name_static(symbol_table),
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
pub fn resolve_names_field_init(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_field_init(symbol_table, self_class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.resolve_names_field_init(symbol_table, self_class_symbol)
}
Expression::Call(call) => {
call.resolve_names_field_init(symbol_table, self_class_symbol)
}
Expression::Identifier(identifier) => {
identifier.resolve_name_field_init(symbol_table, self_class_symbol)
}
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_ctor(symbol_table, self_class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.resolve_names_ctor(symbol_table, self_class_symbol)
}
Expression::Call(call) => call.resolve_names_ctor(symbol_table, self_class_symbol),
Expression::Identifier(identifier) => {
identifier.resolve_name_ctor(symbol_table, self_class_symbol)
}
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_method(symbol_table, self_class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.resolve_names_method(symbol_table, self_class_symbol)
}
Expression::Call(call) => call.resolve_names_method(symbol_table, self_class_symbol),
Expression::Identifier(identifier) => {
identifier.resolve_name_method(symbol_table, self_class_symbol)
}
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
#[deprecated]
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Expression::Binary(binary_expression) => {
binary_expression.check_field_initializer_names(symbol_table, class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.check_field_initializer_names(symbol_table, class_symbol)
}
Expression::Call(call) => {
call.check_field_initializer_names(symbol_table, class_symbol)
}
Expression::Identifier(identifier) => {
if let Some(diagnostic) =
identifier.check_name_as_field_initializer(symbol_table, class_symbol)
{
vec![diagnostic]
} else {
vec![]
}
}
_ => vec![],
}
}
#[deprecated]
pub fn check_constructor_destination_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Expression::Binary(_) => {
panic!()
}
Expression::Negative(_) => {
panic!()
}
Expression::Call(_) => {
panic!()
}
Expression::Identifier(identifier) => {
if let Some(diagnostic) =
identifier.check_constructor_destination_name(symbol_table, class_symbol)
{
vec![diagnostic]
} else {
vec![]
}
}
_ => vec![],
}
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Expression::Binary(binary_expression) => {
binary_expression.check_constructor_local_names(symbol_table, class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.check_constructor_local_names(symbol_table, class_symbol)
}
Expression::Call(call) => {
call.check_constructor_local_names(symbol_table, class_symbol)
}
Expression::Identifier(identifier) => {
if let Some(diagnostic) =
identifier.check_constructor_local_name(symbol_table, class_symbol)
{
vec![diagnostic]
} else {
vec![]
}
}
_ => vec![],
}
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Expression::Binary(binary_expression) => {
binary_expression.check_method_local_names(symbol_table, class_symbol)
}
Expression::Negative(negative_expression) => {
negative_expression.check_method_local_names(symbol_table, class_symbol)
}
Expression::Call(call) => call.check_method_local_names(symbol_table, class_symbol),
Expression::Identifier(identifier) => {
if let Some(diagnostic) =
identifier.check_method_local_name(symbol_table, class_symbol)
{
vec![diagnostic]
} else {
vec![]
}
}
_ => vec![],
}
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
match self {
Expression::Binary(binary_expression) => {
binary_expression.check_static_fn_local_names(symbol_table)
}
Expression::Negative(negative_expression) => {
negative_expression.check_static_fn_local_names(symbol_table)
}
Expression::Call(call) => call.check_static_fn_local_names(symbol_table),
Expression::Identifier(identifier) => {
if let Some(diagnostic) = identifier.check_static_fn_local_name(symbol_table) {
vec![diagnostic]
} else {
vec![]
}
}
Expression::Integer(_) => {
vec![]
}
Expression::Double(_) => {
vec![]
}
Expression::String(_) => {
vec![]
}
}
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_types(nodes_to_symbols, symbols_to_types)
}
Expression::Negative(negative_expression) => {
negative_expression.resolve_types(nodes_to_symbols, symbols_to_types)
}
Expression::Call(call) => call.resolve_types(nodes_to_symbols, symbols_to_types),
Expression::Identifier(identifier) => {
identifier.resolve_type(nodes_to_symbols, symbols_to_types)
}
Expression::Integer(integer_literal) => {
let mut resolved_types = NodesToTypes::new();
resolved_types.insert(
integer_literal.node_id(),
integer_literal.type_info().clone(),
);
(resolved_types, Diagnostics::new())
}
Expression::Double(double_literal) => {
let mut resolved_types = NodesToTypes::new();
resolved_types.insert(double_literal.node_id(), double_literal.type_info().clone());
(resolved_types, Diagnostics::new())
}
Expression::String(string_literal) => {
let mut resolved_types = NodesToTypes::new();
resolved_types.insert(string_literal.node_id(), string_literal.type_info().clone());
(resolved_types, Diagnostics::new())
}
}
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
match self {
Expression::Binary(binary_expression) => {
binary_expression.type_check(symbol_table, types_table)
}
Expression::Negative(negative_expression) => {
negative_expression.type_check(symbol_table, types_table)
}
Expression::Call(call) => call.type_check(symbol_table, types_table),
Expression::Identifier(_) => Ok(()),
Expression::Integer(_) => Ok(()),
Expression::Double(_) => Ok(()),
Expression::String(_) => Ok(()),
}
}
#[deprecated]
pub fn type_info<'a>(
&'a self,
symbol_table: &SymbolTable,
types_table: &'a TypesTable,
) -> &'a TypeInfo {
match self {
Expression::Binary(binary_expression) => binary_expression.type_info(),
Expression::Negative(negative_expression) => negative_expression.type_info(),
Expression::Call(call) => call.return_type_info(symbol_table, types_table),
Expression::Identifier(identifier) => identifier.type_info(symbol_table, types_table),
Expression::Integer(integer_literal) => integer_literal.type_info(),
Expression::Double(double_literal) => double_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::Binary(binary_expression) => binary_expression.source_range(), Expression::Binary(binary_expression) => binary_expression.source_range(),
@ -370,136 +42,4 @@ impl Expression {
Expression::String(string_literal) => string_literal.source_range(), Expression::String(string_literal) => string_literal.source_range(),
} }
} }
pub fn lower_to_ir_operation(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrOperation {
match self {
Expression::Binary(binary_expression) => binary_expression.lower_to_ir_operation(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
),
Expression::Negative(negative_expression) => {
IrOperation::Load(negative_expression.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
))
}
Expression::Call(call) => IrOperation::Call(call.lower_to_ir(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
)),
Expression::Identifier(identifier) => IrOperation::Load(
identifier.lower_to_ir_expression(builder, nodes_to_symbols, symbols_to_types),
),
Expression::Integer(integer_literal) => {
IrOperation::Load(IrExpression::Int(integer_literal.value()))
}
Expression::Double(double_literal) => {
IrOperation::Load(IrExpression::Double(double_literal.value()))
}
Expression::String(string_literal) => {
IrOperation::Load(IrExpression::String(string_literal.content().into()))
}
}
}
pub fn lower_to_ir_expression(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrExpression {
todo!()
}
pub fn to_ir_operation(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrOperation {
match self {
Expression::Binary(binary_expression) => {
binary_expression.to_ir_operation(builder, symbol_table, types_table)
}
Expression::Call(call) => {
IrOperation::Call(call.to_ir(builder, symbol_table, types_table))
}
Expression::Integer(integer_literal) => {
IrOperation::Load(IrExpression::Int(integer_literal.value()))
}
Expression::Double(double_literal) => {
IrOperation::Load(IrExpression::Double(double_literal.value()))
}
Expression::String(string_literal) => {
IrOperation::Load(IrExpression::String(string_literal.content().into()))
}
Expression::Identifier(identifier) => {
IrOperation::Load(identifier.ir_expression(builder, symbol_table, types_table))
}
Expression::Negative(negative_expression) => {
IrOperation::Load(negative_expression.to_ir(builder, symbol_table, types_table))
}
}
}
pub fn to_ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Option<IrExpression> {
match self {
Expression::Binary(binary_expression) => {
Some(binary_expression.to_ir_expression(builder, symbol_table, types_table))
}
Expression::Negative(negative_expression) => {
Some(negative_expression.to_ir(builder, symbol_table, types_table))
}
Expression::Call(call) => {
let ir_call = call.to_ir(builder, symbol_table, types_table);
if matches!(
call.return_type_info(symbol_table, types_table),
TypeInfo::Void
) {
builder
.current_block_mut()
.add_statement(IrStatement::Call(ir_call));
None
} else {
let t_var = todo!();
let as_rc = Rc::new(RefCell::new(t_var));
let assign = IrAssign::new(todo!(), IrOperation::Call(ir_call));
builder
.current_block_mut()
.add_statement(IrStatement::Assign(assign));
Some(IrExpression::Variable(todo!()))
}
}
Expression::Identifier(identifier) => {
Some(identifier.ir_expression(builder, symbol_table, types_table))
}
Expression::Integer(integer_literal) => {
Some(IrExpression::Int(integer_literal.value()))
}
Expression::Double(double_literal) => {
Some(IrExpression::Double(double_literal.value()))
}
Expression::String(string_literal) => {
Some(IrExpression::String(string_literal.content().into()))
}
}
}
} }

View File

@ -1,23 +1,12 @@
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_return::IrReturn;
use crate::ir::ir_statement::IrStatement;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
pub struct ExpressionStatement { pub struct ExpressionStatement {
node_id: NodeId,
expression: Box<Expression>, expression: Box<Expression>,
} }
impl ExpressionStatement { impl ExpressionStatement {
pub fn new(node_id: NodeId, expression: Expression) -> Self { pub fn new(expression: Expression) -> Self {
Self { Self {
node_id,
expression: expression.into(), expression: expression.into(),
} }
} }
@ -25,140 +14,4 @@ impl ExpressionStatement {
pub fn expression(&self) -> &Expression { pub fn expression(&self) -> &Expression {
&self.expression &self.expression
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.expression.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
self.expression.resolve_names_static(symbol_table)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
self.expression
.resolve_names_ctor(symbol_table, self_class_symbol)
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
self.expression
.resolve_names_method(symbol_table, self_class_symbol)
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.expression
.check_constructor_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.expression
.check_method_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
self.expression.check_static_fn_local_names(symbol_table)
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let (mut nodes_to_types, diagnostics) = self
.expression
.resolve_types(nodes_to_symbols, symbols_to_types);
// add self for last-statement type checking
let expression_type_info = nodes_to_types
.get(&self.expression.node_id())
.cloned()
.unwrap();
nodes_to_types.insert(self.node_id, expression_type_info);
(nodes_to_types, diagnostics)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
must_return_type_info: Option<&TypeInfo>,
) -> Result<(), Vec<Diagnostic>> {
self.expression.type_check(symbol_table, types_table)?;
if must_return_type_info.is_some() {
let expression_type = self.expression.type_info(symbol_table, types_table);
let return_type = must_return_type_info.unwrap();
if !return_type.is_assignable_from(expression_type) {
return Err(vec![Diagnostic::new(
&format!(
"Incompatible type on return expression: expected {} but found {}",
return_type, expression_type
),
self.expression.source_range().start(),
self.expression.source_range().end(),
)]);
}
}
Ok(())
}
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
should_return_value: bool,
) {
let ir_expression = self
.expression
.to_ir_expression(builder, symbol_table, types_table);
if ir_expression.is_some() && should_return_value {
builder
.current_block_mut()
.add_statement(IrStatement::Return(IrReturn::new(ir_expression)));
}
}
pub fn lower_to_ir(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
is_return_statement: bool,
) {
let ir_expression = self.expression.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
if is_return_statement {
builder
.current_block_mut()
.add_statement(IrStatement::Return(IrReturn::new(Some(ir_expression))));
}
}
} }

View File

@ -1,18 +1,7 @@
use crate::ast::fqn_context::FqnContext; use crate::ast::NodeId;
use crate::ast::helpers::{
collect_diagnostics_into_mut, collect_parameter_symbols_into, resolve_parameter_names_into,
};
use crate::ast::parameter::Parameter; use crate::ast::parameter::Parameter;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::ast::{NodeId, NodesToSymbols, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics};
use std::rc::Rc; use std::rc::Rc;
pub struct ExternFunction { pub struct ExternFunction {
@ -21,7 +10,6 @@ pub struct ExternFunction {
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
parameters: Vec<Parameter>, parameters: Vec<Parameter>,
return_type: TypeUse, return_type: TypeUse,
scope_id: Option<usize>,
} }
impl ExternFunction { impl ExternFunction {
@ -38,7 +26,6 @@ impl ExternFunction {
declared_name_source_range, declared_name_source_range,
parameters, parameters,
return_type, return_type,
scope_id: None,
} }
} }
@ -65,153 +52,4 @@ impl ExternFunction {
pub fn return_type(&self) -> &TypeUse { pub fn return_type(&self) -> &TypeUse {
&self.return_type &self.return_type
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
let function_scope = symbol_table
.push_function_scope(&format!("extern_function_scope({})", self.declared_name));
for parameter in &mut self.parameters {
parameter.init_scopes(symbol_table, function_scope);
}
self.return_type.init_scopes(symbol_table, function_scope);
symbol_table.pop_scope();
}
pub fn declared_symbols(&self, fqn_context: &FqnContext) -> (Rc<FunctionSymbol>, Vec<Symbol>) {
let mut all_symbols: Vec<Symbol> = Vec::new();
let mut parameter_symbols = Vec::new();
collect_parameter_symbols_into(&self.parameters, &mut all_symbols, &mut parameter_symbols);
let function_symbol = Rc::new(FunctionSymbol::new(
&self.declared_name,
self.declared_name_source_range.clone(),
fqn_context.resolve(self.declared_name()),
true,
false,
self.scope_id.unwrap(),
parameter_symbols,
));
all_symbols.push(Symbol::Function(function_symbol.clone()));
(function_symbol, all_symbols)
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
resolve_parameter_names_into(
&self.parameters,
symbol_table,
&mut names_table,
&mut diagnostics,
);
{
let (ns, mut ds) = self.return_type.resolve_names(symbol_table);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn declared_types(
&self,
nodes_to_symbols: &NodesToSymbols,
) -> (SymbolsToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut symbols_to_types = SymbolsToTypes::new();
for parameter in &self.parameters {
let (type_info, mut ds) = parameter.declared_type(nodes_to_symbols);
let parameter_symbol = nodes_to_symbols.get(&parameter.node_id()).unwrap();
symbols_to_types.insert(parameter_symbol.clone(), type_info);
diagnostics.append(&mut ds);
}
(symbols_to_types, diagnostics)
}
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
for parameter in &self.parameters {
diagnostics.append(&mut parameter.check_names(symbol_table));
}
diagnostics.append(&mut self.return_type.check_names(symbol_table));
diagnostics
}
pub fn gather_types(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) {
let function_symbol = symbol_table
.get_function_symbol_owned(self.scope_id.unwrap(), self.declared_name())
.unwrap();
// self function type
types_table.function_types_mut().insert(
function_symbol.clone(),
TypeInfo::Function(function_symbol.clone()),
);
// return type (temporary)
let resolved_return_type = self
.return_type
.type_info(symbol_table, types_table)
.clone();
types_table
.function_return_types_mut()
.insert(function_symbol, resolved_return_type);
// parameters
for parameter in &self.parameters {
parameter.gather_types_into(symbol_table, types_table);
}
}
fn type_check_parameters(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
diagnostics: &mut Vec<Diagnostic>,
) {
collect_diagnostics_into_mut(
&mut self.parameters,
|p| p.type_check(symbol_table, types_table),
diagnostics,
);
}
fn type_check_return_type(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
diagnostics: &mut Vec<Diagnostic>,
) {
handle_diagnostics!(
self.return_type.type_check(symbol_table, types_table),
diagnostics
);
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
self.type_check_parameters(symbol_table, types_table, &mut diagnostics);
self.type_check_return_type(symbol_table, types_table, &mut diagnostics);
diagnostics_result!(diagnostics)
}
} }

View File

@ -1,15 +1,7 @@
use crate::ast::NodeId;
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::helpers::insert_resolved_names_into;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::ast::{NodeId, NodesToSymbols, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::field_has_no_type_or_init;
use crate::ir::ir_class::IrField;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::field_symbol::FieldSymbol;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
use std::rc::Rc; use std::rc::Rc;
pub struct Field { pub struct Field {
@ -20,7 +12,6 @@ pub struct Field {
is_mut: bool, is_mut: bool,
declared_type: Option<Box<TypeUse>>, declared_type: Option<Box<TypeUse>>,
initializer: Option<Box<Expression>>, initializer: Option<Box<Expression>>,
scope_id: Option<usize>,
} }
impl Field { impl Field {
@ -41,7 +32,6 @@ impl Field {
is_mut, is_mut,
declared_type: declared_type.map(Box::new), declared_type: declared_type.map(Box::new),
initializer: initializer.map(Box::new), initializer: initializer.map(Box::new),
scope_id: None,
} }
} }
@ -64,177 +54,4 @@ impl Field {
pub fn initializer(&self) -> Option<&Expression> { pub fn initializer(&self) -> Option<&Expression> {
self.initializer.as_ref().map(Box::as_ref) self.initializer.as_ref().map(Box::as_ref)
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
if let Some(type_use) = &mut self.declared_type {
type_use.init_scopes(symbol_table, container_scope);
}
if let Some(expression) = &mut self.initializer {
expression.init_scopes(symbol_table, container_scope);
}
}
pub fn scope_id(&self) -> usize {
self.scope_id.unwrap()
}
pub fn make_symbol(&self, field_index: usize) -> FieldSymbol {
FieldSymbol::new(
&self.declared_name,
self.declared_name_source_range.clone(),
self.is_mut,
self.scope_id.unwrap(),
field_index,
)
}
pub fn resolve_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut names_table = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
if let Some(type_use) = &self.declared_type {
let (ns, mut ds) = type_use.resolve_names(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
if let Some(initializer) = &self.initializer {
let (ns, mut ds) = initializer.resolve_names_field_init(symbol_table, class_symbol);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
if let Some(type_use) = &self.declared_type {
diagnostics.append(&mut type_use.check_names(symbol_table));
}
diagnostics
}
#[deprecated]
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
if let Some(initializer) = &self.initializer {
initializer.check_field_initializer_names(symbol_table, class_symbol)
} else {
vec![]
}
}
pub fn gather_types(
&self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
// self field
let field_symbol = symbol_table
.get_field_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
match &self.declared_type {
Some(declared_type) => {
let resolved_type = declared_type.type_info(symbol_table, types_table).clone();
types_table
.field_types_mut()
.insert(field_symbol, resolved_type);
}
None => match &self.initializer {
Some(initializer) => {
let initializer_type = initializer.type_info(symbol_table, types_table).clone();
types_table
.field_types_mut()
.insert(field_symbol, initializer_type);
}
None => {
// this is an error
return Err(vec![field_has_no_type_or_init(
self.declared_name(),
self.declared_name_source_range(),
)]);
}
},
}
Ok(())
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
if let Some(type_use) = &mut self.declared_type {
if let Some(mut type_use_diagnostics) =
type_use.type_check(symbol_table, types_table).err()
{
diagnostics.append(&mut type_use_diagnostics);
}
}
if let Some(initializer) = &mut self.initializer {
if let Some(mut initializer_diagnostics) =
initializer.type_check(symbol_table, types_table).err()
{
diagnostics.append(&mut initializer_diagnostics);
}
}
if !diagnostics.is_empty() {
return Err(diagnostics);
}
// Now check that types are assignable
match self.declared_type.as_ref() {
Some(type_use) => match self.initializer.as_ref() {
Some(initializer) => {
let initializer_type_info = initializer.type_info(symbol_table, types_table);
let declared_type_info = type_use.type_info(symbol_table, types_table);
if declared_type_info.is_assignable_from(initializer_type_info) {
Ok(())
} else {
Err(vec![
Diagnostic::new(
&format!(
"Mismatched types: {} is not assignable to {}",
initializer_type_info, declared_type_info
),
initializer.source_range().start(),
initializer.source_range().end(),
)
.with_reporter(file!(), line!()),
])
}
}
None => Ok(()),
},
None => Ok(()),
}
}
pub fn lower_to_ir_field(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> IrField {
let symbol = nodes_to_symbols.get(&self.node_id).unwrap();
let field_type = symbols_to_types.get(symbol).unwrap();
IrField::new(
self.declared_name.clone(),
symbol.unwrap_field_symbol().field_index(), // todo: this needs to be stored NOT in the symbol
field_type.clone(),
)
}
} }

View File

@ -1,15 +0,0 @@
pub struct Fqn {
parts: Vec<String>,
}
impl Fqn {
pub fn new(parts: &[&str]) -> Self {
Self {
parts: parts.iter().map(|s| s.to_string()).collect(),
}
}
pub fn parts(&self) -> &[String] {
self.parts.as_slice()
}
}

View File

@ -1,23 +0,0 @@
use std::rc::Rc;
pub struct FqnContext {
parts: Vec<Rc<str>>,
}
impl FqnContext {
pub fn new() -> Self {
Self { parts: vec![] }
}
pub fn with_part(&self, part: &Rc<str>) -> Self {
let mut new_parts = self.parts.clone();
new_parts.push(part.clone());
Self { parts: new_parts }
}
pub fn resolve(&self, name: &str) -> Vec<Rc<str>> {
let mut result = self.parts.clone();
result.push(name.into());
result
}
}

View File

@ -1,29 +1,8 @@
use crate::ast::fqn_context::FqnContext; use crate::ast::NodeId;
use crate::ast::fqn_util::fqn_parts_to_string;
use crate::ast::helpers::{
collect_diagnostics_into_enumerated_mut, collect_diagnostics_into_mut,
collect_parameter_symbols_into, insert_declared_types_into, insert_resolved_names_into,
insert_resolved_types_into, resolve_parameter_names_into,
};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::parameter::Parameter; use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement; use crate::ast::statement::Statement;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_function::IrFunction;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics};
use std::ops::Neg;
use std::rc::Rc; use std::rc::Rc;
pub struct Function { pub struct Function {
@ -34,8 +13,6 @@ pub struct Function {
parameters: Vec<Parameter>, parameters: Vec<Parameter>,
return_type: Option<TypeUse>, return_type: Option<TypeUse>,
statements: Vec<Statement>, statements: Vec<Statement>,
container_scope_id: Option<usize>,
function_scope_id: Option<usize>,
} }
impl Function { impl Function {
@ -56,8 +33,6 @@ impl Function {
parameters, parameters,
return_type, return_type,
statements, statements,
container_scope_id: None,
function_scope_id: None,
} }
} }
@ -88,466 +63,4 @@ impl Function {
pub fn statements(&self) -> Vec<&Statement> { pub fn statements(&self) -> Vec<&Statement> {
self.statements.iter().collect() self.statements.iter().collect()
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.container_scope_id = Some(container_scope);
let function_scope =
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
self.function_scope_id = Some(function_scope);
for parameter in &mut self.parameters {
parameter.init_scopes(symbol_table, function_scope);
}
if let Some(type_use) = &mut self.return_type {
type_use.init_scopes(symbol_table, function_scope);
}
let body_scope =
symbol_table.push_block_scope(&format!("body_scope({})", self.declared_name));
for statement in &mut self.statements {
statement.init_scopes(symbol_table, body_scope);
}
symbol_table.pop_scope(); // body
symbol_table.pop_scope(); // function
}
/// Return value contains self FunctionSymbol followed by all symbols (including self symbol).
pub fn declared_symbols(
&self,
fqn_context: &FqnContext,
is_method: bool,
) -> (Rc<FunctionSymbol>, Vec<Symbol>) {
let mut all_symbols: Vec<Symbol> = vec![];
let mut parameter_symbols = Vec::new();
if is_method {
let self_parameter_symbol = Rc::new(ParameterSymbol::new(
&Rc::from("self"),
None,
self.function_scope_id.unwrap(),
));
parameter_symbols.push(self_parameter_symbol.clone());
all_symbols.push(Symbol::Parameter(self_parameter_symbol))
}
collect_parameter_symbols_into(&self.parameters, &mut all_symbols, &mut parameter_symbols);
let function_symbol = Rc::new(FunctionSymbol::new(
&self.declared_name,
self.declared_name_source_range.clone(),
fqn_context.resolve(self.declared_name()),
false,
is_method,
self.container_scope_id.unwrap(),
parameter_symbols,
));
all_symbols.push(Symbol::Function(function_symbol.clone()));
(function_symbol, all_symbols)
}
fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_symbols = NodesToSymbols::new();
resolve_parameter_names_into(
&self.parameters,
symbol_table,
&mut nodes_to_symbols,
&mut diagnostics,
);
if let Some(type_use) = &self.return_type {
let (ns, mut ds) = type_use.resolve_names(symbol_table);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
// insert self function symbol with this node
let function_symbol = symbol_table
.get_function_symbol_owned(self.container_scope_id.unwrap(), &self.declared_name)
.unwrap();
nodes_to_symbols.insert(self.node_id, Symbol::Function(function_symbol));
(nodes_to_symbols, diagnostics)
}
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let (mut nodes_to_symbols, mut diagnostics) = self.resolve_names_common(symbol_table);
for statement in &self.statements {
let (ns, mut ds) = statement.resolve_names_static(symbol_table);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
(nodes_to_symbols, diagnostics)
}
pub fn resolve_names_method(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let (mut nodes_to_symbols, mut diagnostics) = self.resolve_names_common(symbol_table);
for statement in &self.statements {
let (ns, mut ds) = statement.resolve_names_method(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
(nodes_to_symbols, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
for parameter in &self.parameters {
diagnostics.append(&mut parameter.check_names(symbol_table));
}
if let Some(type_use) = &self.return_type {
diagnostics.append(&mut type_use.check_names(symbol_table));
}
diagnostics
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.statements
.iter()
.flat_map(|statement| statement.analyze_method_local_names(symbol_table, class_symbol))
.collect()
}
#[deprecated]
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
self.statements
.iter()
.flat_map(|statement| statement.analyze_static_fn_local_names(symbol_table))
.collect()
}
pub fn declared_types(
&self,
nodes_to_symbols: &NodesToSymbols,
) -> (SymbolsToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut symbols_to_types = SymbolsToTypes::new();
for parameter in &self.parameters {
let symbol = nodes_to_symbols.get(&parameter.node_id()).unwrap();
let (type_info, mut ds) = parameter.declared_type(nodes_to_symbols);
symbols_to_types.insert(symbol.clone(), type_info);
diagnostics.append(&mut ds);
}
// Insert return type as the type of this function symbol
let symbol = nodes_to_symbols.get(&self.node_id).unwrap().clone();
let type_info = match &self.return_type {
None => TypeInfo::Void,
Some(type_use) => {
let (type_info, mut ds) = type_use.declared_type(nodes_to_symbols);
diagnostics.append(&mut ds);
type_info
}
};
symbols_to_types.insert(symbol, type_info);
(symbols_to_types, diagnostics)
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (SymbolsToTypes, NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_types = NodesToTypes::new();
let mut symbols_to_types = symbols_to_types.clone();
for statement in &self.statements {
let (sts, nts, mut ds) = statement.resolve_types(nodes_to_symbols, &symbols_to_types);
insert_declared_types_into(sts, &mut symbols_to_types); // merge!
insert_resolved_types_into(nts, &mut nodes_to_types);
diagnostics.append(&mut ds);
}
// todo: check last statement for return type
(symbols_to_types, nodes_to_types, diagnostics)
}
#[deprecated]
pub fn gather_types(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) {
let function_symbol = symbol_table
.get_function_symbol_owned(self.container_scope_id.unwrap(), self.declared_name())
.unwrap();
// self type (the signature)
types_table.function_types_mut().insert(
function_symbol.clone(),
TypeInfo::Function(function_symbol.clone()),
);
// put return type (temporary, this is deprecated)
if let Some(type_use) = &self.return_type {
let resolved_return_type = type_use.type_info(symbol_table, types_table).clone();
types_table
.function_return_types_mut()
.insert(function_symbol, resolved_return_type);
} else {
types_table
.function_return_types_mut()
.insert(function_symbol, TypeInfo::Void);
}
// parameters
for parameter in &self.parameters {
parameter.gather_types_into(symbol_table, types_table);
}
}
fn get_return_type_info(
types_table: &TypesTable,
function_symbol: &FunctionSymbol,
) -> TypeInfo {
types_table
.function_return_types()
.get(function_symbol)
.cloned()
.unwrap()
}
/// Type checks parameters.
fn type_check_parameters(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
diagnostics: &mut Vec<Diagnostic>,
) {
collect_diagnostics_into_mut(
&mut self.parameters,
|p| p.type_check(symbol_table, types_table),
diagnostics,
)
}
/// Type checks return type.
fn type_check_return_type(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
diagnostics: &mut Vec<Diagnostic>,
) {
if let Some(type_use) = &mut self.return_type {
handle_diagnostics!(type_use.type_check(symbol_table, types_table), diagnostics);
}
}
/// Type checks statements, making sure the last statement matches return type, if necessary.
fn type_check_statements(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
diagnostics: &mut Vec<Diagnostic>,
function_symbol: &FunctionSymbol,
) {
let return_type_info = Self::get_return_type_info(types_table, function_symbol);
let statements_len = self.statements.len();
collect_diagnostics_into_enumerated_mut(
&mut self.statements,
|i, s| {
let is_last = i == statements_len - 1;
if is_last {
s.type_check(symbol_table, types_table, Some(&return_type_info))
} else {
s.type_check(symbol_table, types_table, None)
}
},
diagnostics,
);
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics = vec![];
let function_symbol = symbol_table
.get_function_symbol(self.container_scope_id.unwrap(), self.declared_name())
.unwrap();
// parameters
self.type_check_parameters(symbol_table, types_table, &mut diagnostics);
// return type
self.type_check_return_type(symbol_table, types_table, &mut diagnostics);
// statements
self.type_check_statements(symbol_table, types_table, &mut diagnostics, function_symbol);
diagnostics_result!(diagnostics)
}
/// Converts all parameters to ir. Saves the IrParameter to the associated parameter symbol.
fn parameters_to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) {
for (i, parameter) in self.parameters.iter().enumerate() {
let parameter_symbol = symbol_table
.get_parameter_symbol_owned(parameter.scope_id(), parameter.declared_name())
.unwrap();
let parameter_type_info = types_table
.parameter_types()
.get(&parameter_symbol)
.unwrap();
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
let ir_parameter =
IrParameter::new(parameter_symbol.declared_name(), todo!(), stack_offset);
let as_rc = Rc::new(ir_parameter);
builder.push_parameter(&parameter_symbol, as_rc.clone());
}
}
/// If `class_context.is_some()`, set parameter 0 to the self parameter/variable on the builder.
fn handle_method_case(&self, builder: &mut IrBuilder, class_context: Option<&ClassSymbol>) {
// if we are a method, we need to set the self parameter on the builder
if class_context.is_some() {
let parameter_0 = builder.parameters()[0].clone();
// put it in the self parameter
builder.set_self_parameter_or_variable(IrParameterOrVariable::Parameter(todo!()));
}
}
/// Convert all statements to ir.
fn statements_to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
function_symbol: &FunctionSymbol,
) {
let return_type_info = Self::get_return_type_info(types_table, function_symbol);
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
for (i, statement) in self.statements.iter().enumerate() {
let is_last = i == self.statements.len() - 1;
statement.to_ir(
builder,
symbol_table,
types_table,
should_return_value && is_last,
);
}
}
#[deprecated]
pub fn to_ir(
&self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
class_context: Option<&ClassSymbol>,
) -> IrFunction {
let mut builder = IrBuilder::new();
let function_symbol = symbol_table
.get_function_symbol(self.container_scope_id.unwrap(), self.declared_name())
.unwrap();
// parameters
self.parameters_to_ir(&mut builder, symbol_table, types_table);
let entry_block_id = builder.new_block();
// preamble
self.handle_method_case(&mut builder, class_context);
// body
self.statements_to_ir(&mut builder, symbol_table, types_table, function_symbol);
builder.finish_block();
let entry_block = builder.get_block(entry_block_id).clone();
IrFunction::new(
fqn_parts_to_string(function_symbol.fqn_parts()),
todo!(),
todo!(),
todo!(),
todo!(),
todo!(),
)
}
pub fn lower_to_ir_static(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrFunction {
let mut builder = IrBuilder::new();
let function_symbol = nodes_to_symbols
.get(&self.node_id)
.unwrap()
.unwrap_function_symbol();
// put parameters in builder
for (i, parameter_symbol) in function_symbol.parameters().iter().enumerate() {
let parameter_type_info = symbols_to_types
.get(&Symbol::Parameter(parameter_symbol.clone()))
.unwrap();
let stack_offset = (function_symbol.parameters().len() as isize).neg() + (i as isize);
let ir_parameter = Rc::new(IrParameter::new(
parameter_symbol.declared_name(),
todo!(),
stack_offset,
));
builder.push_parameter(parameter_symbol, ir_parameter);
}
let entry_block_id = builder.new_block();
// lower statements
let return_type_info = symbols_to_types
.get(&Symbol::Function(function_symbol.clone()))
.unwrap();
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
for (i, statement) in self.statements.iter().enumerate() {
let is_last = i == self.statements.len() - 1;
statement.lower_to_ir(
&mut builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
should_return_value && is_last,
);
}
builder.finish_block();
let entry_block = builder.get_block(entry_block_id).clone();
IrFunction::new(
fqn_parts_to_string(function_symbol.fqn_parts()),
todo!(),
todo!(),
todo!(),
todo!(),
todo!(),
)
}
} }

View File

@ -1,22 +1,11 @@
use crate::ast::NodesToSymbols;
use crate::ast::helpers::insert_resolved_names_into;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics};
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub struct GenericParameter { pub struct GenericParameter {
declared_name: Rc<str>, declared_name: Rc<str>,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
extends: Vec<TypeUse>, extends: Vec<TypeUse>,
scope_id: Option<usize>,
generic_parameter_symbol: Option<Rc<RefCell<GenericParameterSymbol>>>,
} }
impl GenericParameter { impl GenericParameter {
@ -29,82 +18,6 @@ impl GenericParameter {
declared_name: declared_name.into(), declared_name: declared_name.into(),
declared_name_source_range, declared_name_source_range,
extends, extends,
scope_id: None,
generic_parameter_symbol: None,
} }
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
for type_use in &mut self.extends {
type_use.init_scopes(symbol_table, container_scope);
}
}
pub fn make_symbol(&self) -> GenericParameterSymbol {
GenericParameterSymbol::new(
&self.declared_name,
&self.declared_name_source_range,
self.scope_id.unwrap(),
)
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
for type_use in &self.extends {
let (ns, mut ds) = type_use.resolve_names(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
}
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
self.extends
.iter()
.flat_map(|type_use| type_use.check_names(symbol_table))
.collect()
}
pub fn gather_types(
&self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
// self param
let generic_parameter_symbol = symbol_table
.get_generic_parameter_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
types_table.generic_parameter_types_mut().insert(
generic_parameter_symbol.clone(),
TypeInfo::GenericType(generic_parameter_symbol),
);
let mut diagnostics = Vec::new();
for type_use in &self.extends {
handle_diagnostics!(
type_use.gather_types(symbol_table, types_table),
diagnostics
);
}
diagnostics_result!(diagnostics)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
// check extends type uses
for type_use in &mut self.extends {
handle_diagnostics!(type_use.type_check(symbol_table, types_table), diagnostics);
}
diagnostics_result!(diagnostics)
}
} }

View File

@ -1,141 +0,0 @@
use crate::ast::fqn_context::FqnContext;
use crate::ast::parameter::Parameter;
use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostics_result;
use crate::symbol::Symbol;
use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol_table::SymbolTable;
use std::rc::Rc;
/// Iterates through all `ts`, running the `f` function, and pushing returned `Diagnostic`s
/// into `diagnostics`.
pub fn collect_diagnostics_into_mut<T>(
ts: &mut [T],
mut f: impl FnMut(&mut T) -> Result<(), Vec<Diagnostic>>,
diagnostics: &mut Vec<Diagnostic>,
) {
ts.iter_mut()
.map(|t| f(t))
.filter_map(Result::err)
.flatten()
.for_each(|d| diagnostics.push(d));
}
/// Like `collect_diagnostics_into` but enumerated.
pub fn collect_diagnostics_into_enumerated_mut<T>(
ts: &mut [T],
mut f: impl FnMut(usize, &mut T) -> Result<(), Vec<Diagnostic>>,
diagnostics: &mut Vec<Diagnostic>,
) {
ts.iter_mut()
.enumerate()
.map(|(i, t)| f(i, t))
.filter_map(Result::err)
.flatten()
.for_each(|d| diagnostics.push(d));
}
pub fn collect_diagnostics_mut<T>(
ts: &mut [T],
mut f: impl FnMut(&mut T) -> Result<(), Vec<Diagnostic>>,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics = ts
.iter_mut()
.map(|t| f(t))
.filter_map(Result::err)
.flatten()
.collect::<Vec<_>>();
diagnostics_result!(diagnostics)
}
pub fn collect_diagnostics<T>(
ts: &[T],
f: impl Fn(&T) -> Result<(), Vec<Diagnostic>>,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics = ts
.iter()
.map(|t| f(t))
.filter_map(Result::err)
.flatten()
.collect::<Vec<_>>();
diagnostics_result!(diagnostics)
}
pub fn collect_diagnostics_single<T>(
ts: &[T],
f: impl Fn(&T) -> Result<(), Diagnostic>,
) -> Result<(), Vec<Diagnostic>> {
let diagnostics = ts
.iter()
.map(|t| f(t))
.filter_map(Result::err)
.collect::<Vec<_>>();
diagnostics_result!(diagnostics)
}
pub fn gather_oks<T, R>(
ts: &mut [T],
mut f: impl FnMut(&mut T) -> Result<R, Vec<Diagnostic>>,
diagnostics: &mut Vec<Diagnostic>,
) -> Vec<R> {
let mut rs: Vec<R> = vec![];
for t in &mut ts[..] {
match f(t) {
Ok(r) => rs.push(r),
Err(mut t_diagnostics) => {
diagnostics.append(&mut t_diagnostics);
}
}
}
rs
}
pub fn resolve_ctor_name(fqn_context: &FqnContext) -> Vec<Rc<str>> {
fqn_context.resolve("ctor") // ctor is a keyword at the language level, should not be callable via normal means
}
pub fn collect_parameter_symbols_into(
parameters: &[Parameter],
all_symbols: &mut Vec<Symbol>,
parameter_symbols: &mut Vec<Rc<ParameterSymbol>>,
) {
for parameter in parameters {
let symbol = Rc::new(parameter.make_symbol());
all_symbols.push(Symbol::Parameter(symbol.clone()));
parameter_symbols.push(symbol);
}
}
pub fn resolve_parameter_names_into(
parameters: &[Parameter],
symbol_table: &SymbolTable,
nodes_to_symbols: &mut NodesToSymbols,
diagnostics: &mut Diagnostics,
) {
for parameter in parameters {
let (ns, mut ds) = parameter.resolve_names(symbol_table);
for (node_id, symbol) in ns {
nodes_to_symbols.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
}
pub fn insert_resolved_names_into(source: NodesToSymbols, destination: &mut NodesToSymbols) {
for (node_id, symbol) in source {
destination.insert(node_id, symbol);
}
}
pub fn insert_declared_types_into(source: SymbolsToTypes, destination: &mut SymbolsToTypes) {
for (symbol, type_info) in source {
destination.insert(symbol, type_info);
}
}
pub fn insert_resolved_types_into(source: NodesToTypes, destination: &mut NodesToTypes) {
for (node_id, type_info) in source {
destination.insert(node_id, type_info);
}
}

View File

@ -1,36 +1,11 @@
use crate::ast::ir_builder::IrBuilder; use crate::ast::NodeId;
use crate::ast::ir_util::get_or_init_field_pointer_variable;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::{
cannot_reassign_immutable_field, not_assignable, outer_class_field_usage,
outer_class_method_usage, self_constructor_used_in_init, self_field_used_in_init,
self_method_used_in_init, symbol_not_found,
};
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol::field_symbol::FieldSymbol;
use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc; use std::rc::Rc;
pub struct Identifier { pub struct Identifier {
node_id: NodeId, node_id: NodeId,
name: Rc<str>, name: Rc<str>,
source_range: SourceRange, source_range: SourceRange,
scope_id: Option<usize>,
} }
impl Identifier { impl Identifier {
@ -39,7 +14,6 @@ impl Identifier {
node_id, node_id,
name: name.into(), name: name.into(),
source_range, source_range,
scope_id: None,
} }
} }
@ -51,629 +25,7 @@ impl Identifier {
&self.name &self.name
} }
pub fn init_scope_id(&mut self, container_scope: usize) {
self.scope_id = Some(container_scope);
}
pub fn scope_id(&self) -> usize {
self.scope_id.unwrap()
}
pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
match symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name) {
None => {
diagnostics.push(symbol_not_found(&self.name, &self.source_range));
}
Some(expressible_symbol) => {
names_table.insert(self.node_id, expressible_symbol.into_symbol());
}
}
(names_table, diagnostics)
}
/// Resolves the name inside an initializer for a field *outside* a constructor.
pub fn resolve_name_field_init(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(class_symbol) => {
self.init_referring_to_class(
self_class_symbol,
&class_symbol,
&mut names_table,
&mut diagnostics,
);
}
ExpressibleSymbol::Field(field_symbol) => {
self.init_referring_to_field(
self_class_symbol,
&field_symbol,
&mut diagnostics,
);
}
ExpressibleSymbol::Function(function_symbol) => {
self.init_referring_to_function(
self_class_symbol,
&function_symbol,
&mut names_table,
&mut diagnostics,
);
}
ExpressibleSymbol::Parameter(_) => {
// Cannot get here, because classes cannot currently be declared in functions
unreachable!()
}
ExpressibleSymbol::Variable(_) => {
// Cannot get here, as classes cannot currently be declared in functions
unreachable!()
}
}
} else {
diagnostics.push(symbol_not_found(&self.name, &self.source_range));
}
(names_table, diagnostics)
}
/// Resolves the name as used in a rhs expression in a constructor.
pub fn resolve_name_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(class_symbol) => {
self.init_referring_to_class(
self_class_symbol,
&class_symbol,
&mut names_table,
&mut diagnostics,
);
}
ExpressibleSymbol::Field(field_symbol) => {
self.init_referring_to_field(
self_class_symbol,
&field_symbol,
&mut diagnostics,
);
}
ExpressibleSymbol::Function(function_symbol) => {
self.init_referring_to_function(
self_class_symbol,
&function_symbol,
&mut names_table,
&mut diagnostics,
);
}
ExpressibleSymbol::Parameter(parameter_symbol) => {
names_table.insert(self.node_id, Symbol::Parameter(parameter_symbol));
}
ExpressibleSymbol::Variable(variable_symbol) => {
names_table.insert(self.node_id, Symbol::Variable(variable_symbol));
}
}
} else {
diagnostics.push(symbol_not_found(&self.name, &self.source_range));
}
(names_table, diagnostics)
}
/// Resolves the name as an LValue in a constructor.
pub fn resolve_name_ctor_destination(
&self,
symbol_table: &SymbolTable,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NodesToSymbols::new();
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(_) => {
// error
diagnostics.push(not_assignable(&self.name, &self.source_range));
}
ExpressibleSymbol::Field(field_symbol) => {
// ok if field has not been initialized yet OR field is mutable
if !initialized_fields.contains(&self.name) {
initialized_fields.insert(self.name.clone());
names_table.insert(self.node_id, Symbol::Field(field_symbol));
} else if !field_symbol.is_mut() {
// error since we are trying to reassign an immutable field
diagnostics.push(cannot_reassign_immutable_field(&self.source_range));
} else {
// mut is ok
names_table.insert(self.node_id, Symbol::Field(field_symbol));
}
}
ExpressibleSymbol::Function(_) => {
diagnostics.push(not_assignable(&self.name, &self.source_range));
}
ExpressibleSymbol::Parameter(_) => {
// assigning to parameter is an error
// we may in the future allow mut on parameters, but it's probably pointless
diagnostics.push(not_assignable(&self.name, &self.source_range));
}
ExpressibleSymbol::Variable(variable_symbol) => {
// ok
names_table.insert(self.node_id, Symbol::Variable(variable_symbol));
}
}
} else {
diagnostics.push(symbol_not_found(&self.name, &self.source_range));
}
(names_table, diagnostics)
}
pub fn resolve_name_method(
&self,
symbol_table: &SymbolTable,
_self_class_symbol: &ClassSymbol, // for future when we have paths?
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut nodes_to_symbols = NodesToSymbols::new();
let maybe_expressible_symbol =
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
match maybe_expressible_symbol {
None => {
diagnostics.push(symbol_not_found(&self.name, &self.source_range));
}
Some(expressible_symbol) => {
nodes_to_symbols.insert(self.node_id, expressible_symbol.into_symbol());
}
}
(nodes_to_symbols, diagnostics)
}
fn init_referring_to_class(
&self,
self_class_symbol: &ClassSymbol,
class_symbol: &Rc<ClassSymbol>,
names_table: &mut NodesToSymbols,
diagnostics: &mut Diagnostics,
) {
// Check against recursively constructing this class.
// This is not future-proof, as we will eventually allow reference to the self class, which
// would (theoretically) be assigned to an instance field.
if self_class_symbol == class_symbol.as_ref() {
diagnostics.push(self_constructor_used_in_init(&self.source_range));
} else {
names_table.insert(self.node_id, Symbol::Class(class_symbol.clone()));
}
}
fn init_referring_to_field(
&self,
self_class_symbol: &ClassSymbol,
field_symbol: &FieldSymbol,
diagnostics: &mut Diagnostics,
) {
if self_class_symbol
.fields()
.contains_key(field_symbol.declared_name())
{
diagnostics.push(self_field_used_in_init(&self.source_range));
} else {
diagnostics.push(outer_class_field_usage(&self.source_range));
}
}
fn init_referring_to_function(
&self,
self_class_symbol: &ClassSymbol,
function_symbol: &Rc<FunctionSymbol>,
names_table: &mut NodesToSymbols,
diagnostics: &mut Diagnostics,
) {
if self_class_symbol
.functions()
.contains_key(function_symbol.declared_name())
{
diagnostics.push(self_method_used_in_init(&self.source_range));
} else if function_symbol.is_method() {
diagnostics.push(outer_class_method_usage(&self.source_range));
} else {
names_table.insert(self.node_id, Symbol::Function(function_symbol.clone()));
}
}
/// Check against recursively constructing this class.
#[deprecated]
fn check_self_constructor_use(
&self,
context_class_symbol: &ClassSymbol,
class_symbol: &ClassSymbol,
) -> Option<Diagnostic> {
// this is not future-proof, as we will eventually allow reference to the self class, which
// would (theoretically) be assigned to an instance field
if context_class_symbol == class_symbol {
Some(self_constructor_used_in_init(&self.source_range))
} else {
None
}
}
/// Check against using this or outer class' bare fields.
#[deprecated]
fn check_self_or_outer_field_use(
&self,
context_class_symbol: &ClassSymbol,
field_symbol: &FieldSymbol,
) -> Option<Diagnostic> {
// Usage of a bare field will always be an error, whether in this class or an outer class
if context_class_symbol
.fields()
.contains_key(field_symbol.declared_name())
{
Some(self_field_used_in_init(&self.source_range))
} else {
Some(outer_class_field_usage(&self.source_range))
}
}
/// Check against using self or outer class methods.
#[deprecated]
fn check_self_or_outer_method_use(
&self,
context_class_symbol: &ClassSymbol,
function_symbol: &FunctionSymbol,
) -> Option<Diagnostic> {
if context_class_symbol
.functions()
.contains_key(function_symbol.declared_name())
{
// Can only use Self static functions, which we don't have yet
Some(self_method_used_in_init(&self.source_range))
} else if function_symbol.is_method() {
// Can only use outer class static functions, which we don't have yet
Some(outer_class_method_usage(&self.source_range))
} else {
None
}
}
#[deprecated]
pub fn check_name_as_field_initializer(
&self,
symbol_table: &SymbolTable,
context_class_symbol: &ClassSymbol,
) -> Option<Diagnostic> {
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(class_symbol) => {
self.check_self_constructor_use(context_class_symbol, &class_symbol)
}
ExpressibleSymbol::Field(field_symbol) => {
self.check_self_or_outer_field_use(context_class_symbol, &field_symbol)
}
ExpressibleSymbol::Function(function_symbol) => {
self.check_self_or_outer_method_use(context_class_symbol, &function_symbol)
}
ExpressibleSymbol::Parameter(_) => {
// Cannot get here, because classes cannot currently be declared in functions
unreachable!()
}
ExpressibleSymbol::Variable(_) => {
// Cannot get here, as classes cannot currently be declared in functions
unreachable!()
}
}
} else {
Some(symbol_not_found(&self.name, &self.source_range))
}
}
#[deprecated]
pub fn check_constructor_destination_name(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Option<Diagnostic> {
let expressible_symbol =
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(expressible_symbol) = expressible_symbol {
match expressible_symbol {
ExpressibleSymbol::Class(_) => {
panic!("Class is not an L value")
}
ExpressibleSymbol::Field(field_symbol) => {
// This is just a stop-gap for now. We need to decide if we are going to do
// field assignment analysis (whether it's initialized already, if it's mut,
// etc.) during name checking or during type checking.
None
}
ExpressibleSymbol::Function(_) => {
panic!("Function is not an L value")
}
ExpressibleSymbol::Parameter(_) => {
panic!("Parameter is not an L value")
}
ExpressibleSymbol::Variable(variable_symbol) => {
// Again, a stop-gap.
None
}
}
} else {
Some(symbol_not_found(&self.name, &self.source_range))
}
}
#[deprecated]
pub fn check_constructor_local_name(
&self,
symbol_table: &SymbolTable,
context_class_symbol: &ClassSymbol,
) -> Option<Diagnostic> {
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(class_symbol) => {
self.check_self_constructor_use(context_class_symbol, &class_symbol)
}
ExpressibleSymbol::Field(field_symbol) => {
self.check_self_or_outer_field_use(context_class_symbol, &field_symbol)
}
ExpressibleSymbol::Function(function_symbol) => {
self.check_self_or_outer_method_use(context_class_symbol, &function_symbol)
}
ExpressibleSymbol::Parameter(_) => None,
ExpressibleSymbol::Variable(_) => None,
}
} else {
Some(symbol_not_found(&self.name, &self.source_range))
}
}
#[deprecated]
pub fn check_method_local_name(
&self,
symbol_table: &SymbolTable,
context_class_symbol: &ClassSymbol,
) -> Option<Diagnostic> {
let symbol = symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
if let Some(symbol) = symbol {
match symbol {
ExpressibleSymbol::Class(_) => {
None // all class usages should be ok
}
ExpressibleSymbol::Field(field_symbol) => {
// Must be a reference to a field in this class
if context_class_symbol
.fields()
.contains_key(field_symbol.declared_name())
{
None
} else {
Some(outer_class_field_usage(&self.source_range))
}
}
ExpressibleSymbol::Function(function_symbol) => {
// Must be a method in this class
if function_symbol.is_method()
&& !context_class_symbol
.functions()
.contains_key(function_symbol.declared_name())
{
Some(outer_class_method_usage(&self.source_range))
} else {
None
}
}
ExpressibleSymbol::Parameter(_) => {
None // ok
}
ExpressibleSymbol::Variable(_) => {
None // ok
}
}
} else {
Some(symbol_not_found(&self.name, &self.source_range))
}
}
/// WARNING: this is not appropriate (yet) for class static functions.
#[deprecated]
pub fn check_static_fn_local_name(&self, symbol_table: &SymbolTable) -> Option<Diagnostic> {
if symbol_table
.find_expressible_symbol(self.scope_id.unwrap(), &self.name)
.is_some()
{
None
} else {
Some(symbol_not_found(&self.name, &self.source_range))
}
}
pub fn source_range(&self) -> &SourceRange { pub fn source_range(&self) -> &SourceRange {
&self.source_range &self.source_range
} }
pub fn resolve_type(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let self_symbol = nodes_to_symbols.get(&self.node_id).unwrap();
let type_info = symbols_to_types.get(self_symbol).unwrap();
let mut resolved_types = NodesToTypes::new();
resolved_types.insert(self.node_id, type_info.clone());
(resolved_types, Diagnostics::new())
}
#[deprecated]
pub fn type_info<'a>(
&self,
symbol_table: &SymbolTable,
types_table: &'a TypesTable,
) -> &'a TypeInfo {
let expressible_symbol = symbol_table
.find_expressible_symbol(self.scope_id.unwrap(), &self.name)
.unwrap();
match expressible_symbol {
ExpressibleSymbol::Class(class_symbol) => {
types_table.class_types().get(&class_symbol).unwrap()
}
ExpressibleSymbol::Field(field_symbol) => {
types_table.field_types().get(&field_symbol).unwrap()
}
ExpressibleSymbol::Function(function_symbol) => types_table
.function_types()
.get(&function_symbol)
.expect(&format!(
"Unable to get function type for {:?}",
function_symbol
)),
ExpressibleSymbol::Parameter(parameter_symbol) => types_table
.parameter_types()
.get(&parameter_symbol)
.unwrap(),
ExpressibleSymbol::Variable(variable_symbol) => {
types_table.variable_types().get(&variable_symbol).unwrap()
}
}
}
pub fn lower_to_ir_expression(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> IrExpression {
let symbol = nodes_to_symbols.get(&self.node_id).unwrap();
match &symbol.unwrap_expressible_symbol() {
ExpressibleSymbol::Class(_class_symbol) => {
todo!()
}
ExpressibleSymbol::Field(field_symbol) => {
let field_type = symbols_to_types.get(symbol).unwrap();
let read_destination = Rc::new(RefCell::new(todo!()));
let ir_read_field = IrReadField::new(todo!());
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
todo!(),
IrOperation::ReadField(ir_read_field),
)));
IrExpression::Variable(todo!())
}
ExpressibleSymbol::Function(_function_symbol) => {
todo!()
}
ExpressibleSymbol::Parameter(parameter_symbol) => IrExpression::Parameter(todo!()),
ExpressibleSymbol::Variable(variable_symbol) => IrExpression::Variable(todo!()),
}
}
pub fn ir_expression(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrExpression {
let expressible_symbol = symbol_table
.find_expressible_symbol(self.scope_id.unwrap(), &self.name)
.unwrap();
match expressible_symbol {
ExpressibleSymbol::Class(class_symbol) => {
todo!()
}
ExpressibleSymbol::Field(field_symbol) => {
let field_type = types_table.field_types().get(&field_symbol).unwrap();
let read_destination = todo!();
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
let ir_read_field = IrReadField::new(todo!());
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
todo!(),
IrOperation::ReadField(ir_read_field),
)));
IrExpression::Variable(todo!())
}
ExpressibleSymbol::Function(_) => {
panic!("Cannot yet get ir-variable for FunctionSymbol")
}
ExpressibleSymbol::Parameter(parameter_symbol) => {
let parameters_map = builder.parameters_map();
let ir_parameter = parameters_map.get(&parameter_symbol).unwrap();
IrExpression::Parameter(todo!())
}
ExpressibleSymbol::Variable(variable_symbol) => {
let ir_variable = builder.local_variables().get(&variable_symbol).unwrap();
IrExpression::Variable(todo!())
}
}
}
}
#[cfg(test)]
mod tests {
use crate::ast::identifier::Identifier;
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::variable_symbol::VariableSymbol;
use crate::symbol_table::SymbolTable;
use std::rc::Rc;
#[test]
fn inits_scope_id() {
let mut identifier = Identifier::new(0, "foo", SourceRange::new(0, 0));
identifier.init_scope_id(42);
assert_eq!(identifier.scope_id(), 42);
}
#[test]
fn resolves_static_foo() {
let mut identifier = Identifier::new(0, "foo", SourceRange::new(0, 0));
let mut symbol_table = SymbolTable::new();
symbol_table.push_module_scope("foo module");
symbol_table.push_function_scope("foo function");
let scope_id = symbol_table.push_block_scope("foo block");
identifier.init_scope_id(scope_id);
let variable_symbol = Rc::new(VariableSymbol::new(
&"foo".into(),
&SourceRange::new(0, 0),
false,
scope_id,
));
symbol_table.insert_variable_symbol(variable_symbol.clone());
let (nodes_to_symbols, diagnostics) = identifier.resolve_name_static(&symbol_table);
assert_eq!(diagnostics.len(), 0);
assert_eq!(nodes_to_symbols.len(), 1);
let symbol = nodes_to_symbols.get(&identifier.node_id()).unwrap();
match symbol {
Symbol::Variable(matched_variable_symbol) => {
assert_eq!(&variable_symbol, matched_variable_symbol);
}
_ => panic!(),
}
}
} }

View File

@ -1,169 +0,0 @@
use crate::ir::ir_block::IrBlock;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol::variable_symbol::VariableSymbol;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
pub struct IrBuilder {
parameters: Vec<(Rc<ParameterSymbol>, Rc<IrParameter>)>,
local_variables: HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
block_counter: usize,
t_var_counter: usize,
blocks: HashMap<usize, Rc<RefCell<IrBlock>>>,
current_block_builder: Option<IrBlockBuilder>,
self_parameter_or_variable: Option<IrParameterOrVariable>,
field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
mut_field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
}
impl IrBuilder {
pub fn new() -> Self {
Self {
parameters: vec![],
local_variables: HashMap::new(),
block_counter: 0,
t_var_counter: 0,
blocks: HashMap::new(),
current_block_builder: None,
self_parameter_or_variable: None,
field_variables: HashMap::new(),
mut_field_variables: HashMap::new(),
}
}
pub fn local_variables(&self) -> &HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>> {
&self.local_variables
}
pub fn local_variables_mut(
&mut self,
) -> &mut HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>> {
&mut self.local_variables
}
pub fn parameters(&self) -> Vec<&Rc<IrParameter>> {
self.parameters
.iter()
.map(|(_, ir_parameter)| ir_parameter)
.collect()
}
pub fn parameters_map(&self) -> HashMap<Rc<ParameterSymbol>, Rc<IrParameter>> {
let mut map = HashMap::new();
for (name, ir_parameter) in &self.parameters {
map.insert(name.clone(), ir_parameter.clone());
}
map
}
pub fn push_parameter(
&mut self,
parameter_symbol: &Rc<ParameterSymbol>,
parameter: Rc<IrParameter>,
) {
self.parameters.push((parameter_symbol.clone(), parameter));
}
pub fn new_block(&mut self) -> usize {
let block_id = self.block_counter;
self.block_counter += 1;
let block_builder = IrBlockBuilder::new(block_id);
self.current_block_builder = Some(block_builder);
block_id
}
pub fn get_block(&mut self, block_id: usize) -> &Rc<RefCell<IrBlock>> {
self.blocks
.get(&block_id)
.expect(&format!("Block {} not found", block_id))
}
pub fn current_block_mut(&mut self) -> &mut IrBlockBuilder {
self.current_block_builder
.as_mut()
.expect("No current block builder")
}
pub fn current_block(&self) -> &IrBlockBuilder {
self.current_block_builder
.as_ref()
.expect("No current block")
}
pub fn finish_block(&mut self) {
let builder = self
.current_block_builder
.take()
.expect("No current block builder");
let block = builder.build();
self.blocks.insert(block.id(), Rc::new(RefCell::new(block)));
}
pub fn new_t_var(&mut self) -> String {
let id = self.t_var_counter;
self.t_var_counter += 1;
format!("t{}", id)
}
pub fn set_self_parameter_or_variable(
&mut self,
self_parameter_or_variable: IrParameterOrVariable,
) {
self.self_parameter_or_variable = Some(self_parameter_or_variable);
}
pub fn self_parameter_or_variable(&self) -> &IrParameterOrVariable {
self.self_parameter_or_variable.as_ref().unwrap()
}
pub fn field_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&self.field_variables
}
pub fn field_pointer_variables_mut(
&mut self,
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&mut self.field_variables
}
pub fn field_mut_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&self.mut_field_variables
}
pub fn field_mut_pointer_variables_mut(
&mut self,
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&mut self.mut_field_variables
}
}
pub struct IrBlockBuilder {
id: usize,
statements: Vec<IrStatement>,
}
impl IrBlockBuilder {
pub fn new(id: usize) -> Self {
Self {
id,
statements: vec![],
}
}
pub fn id(&self) -> usize {
self.id
}
pub fn add_statement(&mut self, statement: IrStatement) {
self.statements.push(statement);
}
pub fn build(self) -> IrBlock {
IrBlock::new(self.id, &format!("b{}", self.id), self.statements)
}
}

View File

@ -1,77 +0,0 @@
use crate::ast::ir_builder::IrBuilder;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::symbol::field_symbol::FieldSymbol;
use crate::type_info::TypeInfo;
use std::cell::RefCell;
use std::rc::Rc;
pub fn get_or_init_field_pointer_variable<'a>(
builder: &'a mut IrBuilder,
field_symbol: &Rc<FieldSymbol>,
field_type: &TypeInfo,
) -> &'a Rc<RefCell<IrVariable>> {
// This following should work because blocks are flat in the ir; if a variable is defined in the
// ir block from this point forward, it's available to all subsequent blocks.
if !builder
.field_pointer_variables()
.contains_key(field_symbol.declared_name())
{
let field_ref_variable = todo!();
let as_rc = Rc::new(RefCell::new(field_ref_variable));
let to_insert = as_rc.clone();
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
todo!(),
IrOperation::GetFieldRef(IrGetFieldRef::new(
self_parameter_or_variable.clone(),
field_symbol.field_index(),
)),
)));
builder
.field_pointer_variables_mut()
.insert(field_symbol.declared_name_owned(), to_insert);
}
builder
.field_pointer_variables()
.get(field_symbol.declared_name())
.unwrap()
}
pub fn get_or_init_mut_field_pointer_variable<'a>(
builder: &'a mut IrBuilder,
field_symbol: &Rc<FieldSymbol>,
field_type: &TypeInfo,
) -> &'a Rc<RefCell<IrVariable>> {
if !builder
.field_mut_pointer_variables()
.contains_key(field_symbol.declared_name())
{
let mut_field_pointer_variable = todo!();
let as_rc = Rc::new(RefCell::new(mut_field_pointer_variable));
let to_insert = as_rc.clone();
let self_parameter_or_variable = builder.self_parameter_or_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
todo!(),
IrOperation::GetFieldRefMut(IrGetFieldRefMut::new(
self_parameter_or_variable.clone(),
field_symbol.field_index(),
)),
)));
builder
.field_mut_pointer_variables_mut()
.insert(field_symbol.declared_name_owned(), to_insert);
}
builder
.field_mut_pointer_variables()
.get(field_symbol.declared_name())
.unwrap()
}

View File

@ -1,20 +1,6 @@
use crate::ast::NodeId;
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::helpers::{insert_resolved_names_into, insert_resolved_types_into};
use crate::ast::ir_builder::IrBuilder;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::variable_symbol::VariableSymbol;
use crate::symbol_table::SymbolTable;
use crate::symbol_table::util::try_insert_symbol_into;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub struct LetStatement { pub struct LetStatement {
@ -23,7 +9,6 @@ pub struct LetStatement {
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
is_mut: bool, is_mut: bool,
initializer: Box<Expression>, initializer: Box<Expression>,
scope_id: Option<usize>,
} }
impl LetStatement { impl LetStatement {
@ -40,7 +25,6 @@ impl LetStatement {
declared_name_source_range, declared_name_source_range,
is_mut, is_mut,
initializer: initializer.into(), initializer: initializer.into(),
scope_id: None,
} }
} }
@ -67,295 +51,4 @@ impl LetStatement {
pub fn initializer(&self) -> &Expression { pub fn initializer(&self) -> &Expression {
&self.initializer &self.initializer
} }
pub fn initializer_mut(&mut self) -> &mut Expression {
&mut self.initializer
}
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
self.initializer.init_scopes(symbol_table, container_scope);
}
pub fn scope_id(&self) -> usize {
self.scope_id.unwrap()
}
fn make_and_insert_variable_symbol(
&self,
symbol_table: &mut SymbolTable,
) -> Option<Diagnostic> {
let variable_symbol = Rc::new(VariableSymbol::new(
&self.declared_name,
&self.declared_name_source_range,
self.is_mut,
self.scope_id.unwrap(),
));
try_insert_symbol_into(Symbol::Variable(variable_symbol), symbol_table).err()
}
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut names_table = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
{
let (ns, mut ds) = self.initializer.resolve_names_static(symbol_table);
insert_resolved_names_into(ns, &mut names_table);
diagnostics.append(&mut ds);
}
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
(names_table, diagnostics)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut nodes_to_symbols = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
{
let (ns, mut ds) = self
.initializer
.resolve_names_ctor(symbol_table, self_class_symbol);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
(nodes_to_symbols, diagnostics)
}
pub fn resolve_names_method(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
let mut nodes_to_symbols = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
{
let (ns, mut ds) = self
.initializer
.resolve_names_method(symbol_table, self_class_symbol); // todo
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
(nodes_to_symbols, diagnostics)
}
#[deprecated]
pub fn analyze_constructor_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
diagnostics.append(
&mut self
.initializer
.check_constructor_local_names(symbol_table, class_symbol),
);
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
diagnostics
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
diagnostics.append(
&mut self
.initializer
.check_method_local_names(symbol_table, class_symbol),
);
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
diagnostics
}
#[deprecated]
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = Vec::new();
diagnostics.append(&mut self.initializer.check_static_fn_local_names(symbol_table));
if let Some(diagnostic) = self.make_and_insert_variable_symbol(symbol_table) {
diagnostics.push(diagnostic);
}
diagnostics
}
pub fn resolve_types(
&self,
resolved_symbols: &NodesToSymbols,
resolved_symbol_type_infos: &SymbolsToTypes,
) -> (SymbolsToTypes, NodesToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut resolved_types = NodesToTypes::new();
{
let (rts, mut ds) = self
.initializer
.resolve_types(resolved_symbols, resolved_symbol_type_infos);
insert_resolved_types_into(rts, &mut resolved_types);
diagnostics.append(&mut ds);
}
let initializer_resolved_type = resolved_types.get(&self.initializer.node_id()).unwrap();
let self_symbol = resolved_symbols.get(&self.node_id).unwrap();
let mut resolved_symbol_type_infos = resolved_symbol_type_infos.clone();
resolved_symbol_type_infos.insert(self_symbol.clone(), initializer_resolved_type.clone());
(resolved_symbol_type_infos, resolved_types, diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.initializer.type_check(symbol_table, types_table)?;
// TODO: this is wrong. We need to check assignability
let initializer_type_info = self
.initializer
.type_info(symbol_table, types_table)
.clone();
let variable_symbol = symbol_table
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
types_table
.variable_types_mut()
.insert(variable_symbol, initializer_type_info);
Ok(())
}
fn make_vr_variable(&self, builder: &mut IrBuilder, destination_type: &TypeInfo) -> IrVariable {
todo!()
}
fn make_stack_variable(
&self,
builder: &mut IrBuilder,
destination_type: &TypeInfo,
offset: isize,
) -> IrVariable {
todo!()
}
pub fn get_destination_symbol(&self, symbol_table: &SymbolTable) -> Rc<VariableSymbol> {
symbol_table
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap()
}
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) {
let init_operation = self
.initializer
.to_ir_operation(builder, symbol_table, types_table);
let destination_symbol = self.get_destination_symbol(symbol_table);
let destination_type = types_table
.variable_types()
.get(&destination_symbol)
.unwrap();
let destination_vr_variable = self.make_vr_variable(builder, destination_type);
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
let ir_assign = IrAssign::new(todo!(), init_operation);
builder
.local_variables_mut()
.insert(destination_symbol, as_rc.clone());
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
}
pub fn to_repl_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
destination_stack_offset: isize,
) -> Rc<RefCell<IrVariable>> {
let init_operation = self
.initializer
.to_ir_operation(builder, symbol_table, types_table);
let destination_symbol = self.get_destination_symbol(symbol_table);
let destination_type = types_table
.variable_types()
.get(&destination_symbol)
.unwrap();
let destination_stack_variable =
self.make_stack_variable(builder, destination_type, destination_stack_offset);
let as_rc = Rc::new(RefCell::new(destination_stack_variable));
let ir_assign = IrAssign::new(todo!(), init_operation);
// do not need to save variable to builder as a new one is created for each repl function
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
as_rc
}
pub fn lower(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) {
let init_operation = self.initializer.lower_to_ir_operation(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
let destination_symbol = nodes_to_symbols.get(&self.node_id).unwrap();
let destination_type_info = symbols_to_types.get(destination_symbol).unwrap();
let vr_variable = Rc::new(RefCell::new(todo!()));
// save local variable to builder
builder.local_variables_mut().insert(
destination_symbol.unwrap_variable_symbol().clone(),
vr_variable.clone(),
);
let ir_assign = IrAssign::new(todo!(), init_operation);
builder
.current_block_mut()
.add_statement(IrStatement::Assign(ir_assign));
}
} }

View File

@ -1,9 +1,3 @@
use crate::symbol::Symbol;
use crate::symbol::function_symbol::FunctionSymbol;
use crate::type_info::TypeInfo;
use std::collections::HashMap;
use std::rc::Rc;
pub mod assign_statement; pub mod assign_statement;
pub mod binary_expression; pub mod binary_expression;
pub mod call; pub mod call;
@ -15,16 +9,10 @@ pub mod expression;
pub mod expression_statement; pub mod expression_statement;
pub mod extern_function; pub mod extern_function;
pub mod field; pub mod field;
pub mod fqn;
pub mod fqn_context;
pub mod fqn_util;
pub mod function; pub mod function;
pub mod generic_parameter; pub mod generic_parameter;
mod helpers;
pub mod identifier; pub mod identifier;
pub mod integer_literal; pub mod integer_literal;
pub mod ir_builder;
pub(crate) mod ir_util;
pub mod let_statement; pub mod let_statement;
pub mod negative_expression; pub mod negative_expression;
pub mod parameter; pub mod parameter;
@ -33,7 +21,3 @@ pub mod string_literal;
pub mod type_use; pub mod type_use;
pub type NodeId = usize; pub type NodeId = usize;
pub type NodesToSymbols = HashMap<NodeId, Symbol>;
pub type SymbolsToTypes = HashMap<Symbol, TypeInfo>;
pub type NodesToTypes = HashMap<NodeId, TypeInfo>;
pub type FunctionReturnTypes = HashMap<Rc<FunctionSymbol>, TypeInfo>;

View File

@ -1,27 +1,11 @@
use crate::ast::NodeId;
use crate::ast::expression::Expression; use crate::ast::expression::Expression;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::unary_incompatible_type;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_binary_operation::{IrBinaryOperation, IrBinaryOperator};
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::cell::RefCell;
use std::rc::Rc;
pub struct NegativeExpression { pub struct NegativeExpression {
node_id: NodeId, node_id: NodeId,
operand: Box<Expression>, operand: Box<Expression>,
source_range: SourceRange, source_range: SourceRange,
type_info: Option<TypeInfo>,
} }
impl NegativeExpression { impl NegativeExpression {
@ -30,7 +14,6 @@ impl NegativeExpression {
node_id, node_id,
operand: operand.into(), operand: operand.into(),
source_range, source_range,
type_info: None,
} }
} }
@ -45,261 +28,4 @@ impl NegativeExpression {
pub fn operand(&self) -> &Expression { pub fn operand(&self) -> &Expression {
&self.operand &self.operand
} }
pub fn operand_mut(&mut self) -> &mut Expression {
&mut self.operand
}
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.operand.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
self.operand.resolve_names_static(symbol_table)
}
pub fn resolve_names_field_init(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
self.operand
.resolve_names_field_init(symbol_table, self_class_symbol)
}
pub fn resolve_names_ctor(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
self.operand
.resolve_names_ctor(symbol_table, self_class_symbol)
}
pub fn resolve_names_method(
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
self.operand
.resolve_names_method(symbol_table, self_class_symbol)
}
#[deprecated]
pub fn check_field_initializer_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_field_initializer_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_constructor_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
self.operand
.check_method_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
self.operand.check_static_fn_local_names(symbol_table)
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let (mut nodes_to_types, mut diagnostics) = self
.operand
.resolve_types(nodes_to_symbols, symbols_to_types);
let type_info = nodes_to_types.get(&self.operand.node_id()).unwrap();
if type_info.can_negate() {
nodes_to_types.insert(self.node_id, type_info.negate_result());
} else {
diagnostics.push(unary_incompatible_type(
&self.source_range,
"negation",
type_info,
));
nodes_to_types.insert(self.node_id, TypeInfo::PlaceholderError);
}
(nodes_to_types, diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.operand.type_check(symbol_table, types_table)?;
let type_info = self.operand.type_info(symbol_table, types_table);
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 lower_to_ir_expression(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
) -> IrExpression {
let base_ir_expression = self.operand.lower_to_ir_expression(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
match base_ir_expression {
IrExpression::Parameter(ir_parameter) => {
let destination = Rc::new(RefCell::new(todo!()));
todo!()
// let rhs = match todo!() {
// TypeInfo::Integer => IrExpression::Int(-1),
// TypeInfo::Double => IrExpression::Double(-1.0),
// _ => panic!(),
// };
//
// let operation = IrOperation::Binary(IrBinaryOperation::new(
// IrExpression::Parameter(ir_parameter),
// rhs,
// IrBinaryOperator::Multiply,
// ));
//
// let ir_assign = IrAssign::new(destination.clone(), operation);
// builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(ir_assign));
//
// IrExpression::Variable(destination)
}
IrExpression::Variable(ir_variable) => {
let destination = Rc::new(RefCell::new(todo!()));
todo!()
// let rhs = match ir_variable.borrow().type_info() {
// TypeInfo::Integer => IrExpression::Int(-1),
// TypeInfo::Double => IrExpression::Double(-1.0),
// _ => panic!(),
// };
//
// let operation = IrOperation::Binary(IrBinaryOperation::new(
// IrExpression::Variable(ir_variable),
// rhs,
// IrBinaryOperator::Multiply,
// ));
//
// let ir_assign = IrAssign::new(destination.clone(), operation);
// builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(ir_assign));
// IrExpression::Variable(destination)
}
IrExpression::Int(i) => IrExpression::Int(i * -1),
IrExpression::Double(d) => IrExpression::Double(d * -1.0),
IrExpression::String(_) => {
panic!();
}
}
}
#[deprecated]
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> IrExpression {
let operand_as_ir = self
.operand
.to_ir_expression(builder, symbol_table, types_table)
.expect("Attempt to negate non-value expression");
match operand_as_ir {
IrExpression::Parameter(parameter) => {
let destination = Rc::new(RefCell::new(todo!()));
todo!()
// let rhs = match todo!() {
// TypeInfo::Integer => IrExpression::Int(-1),
// TypeInfo::Double => IrExpression::Double(-1.0),
// _ => panic!("Trying to multiply with a non-integer/double"),
// };
//
// let operation = IrOperation::Binary(IrBinaryOperation::new(
// IrExpression::Parameter(parameter),
// rhs,
// IrBinaryOperator::Multiply,
// ));
//
// let assign = IrAssign::new(destination.clone(), operation);
// builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(assign));
//
// IrExpression::Variable(destination)
}
IrExpression::Variable(variable) => {
let destination = Rc::new(RefCell::new(todo!()));
todo!()
// let rhs = match variable.borrow().type_info() {
// TypeInfo::Integer => IrExpression::Int(-1),
// TypeInfo::Double => IrExpression::Double(-1.0),
// _ => panic!("Trying to multiply with a non-integer/double"),
// };
//
// let operation = IrOperation::Binary(IrBinaryOperation::new(
// IrExpression::Variable(variable),
// rhs,
// IrBinaryOperator::Multiply,
// ));
//
// let assign = IrAssign::new(destination.clone(), operation);
// builder
// .current_block_mut()
// .add_statement(IrStatement::Assign(assign));
//
// IrExpression::Variable(destination)
}
IrExpression::Int(i) => IrExpression::Int(i * -1),
IrExpression::Double(d) => IrExpression::Double(d * -1.0),
IrExpression::String(_) => {
panic!("Attempt to negate IrExpression::String")
}
}
}
pub fn type_info(&self) -> &TypeInfo {
self.type_info.as_ref().unwrap()
}
} }

View File

@ -1,11 +1,6 @@
use crate::ast::NodeId;
use crate::ast::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::ast::{NodeId, NodesToSymbols};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::rc::Rc; use std::rc::Rc;
pub struct Parameter { pub struct Parameter {
@ -13,7 +8,6 @@ pub struct Parameter {
declared_name: Rc<str>, declared_name: Rc<str>,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
type_use: TypeUse, type_use: TypeUse,
scope_id: Option<usize>,
} }
impl Parameter { impl Parameter {
@ -28,7 +22,6 @@ impl Parameter {
declared_name: declared_name.into(), declared_name: declared_name.into(),
declared_name_source_range, declared_name_source_range,
type_use, type_use,
scope_id: None,
} }
} }
@ -51,54 +44,4 @@ impl Parameter {
pub fn type_use(&self) -> &TypeUse { pub fn type_use(&self) -> &TypeUse {
&self.type_use &self.type_use
} }
pub fn scope_id(&self) -> usize {
self.scope_id.unwrap()
}
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
self.type_use.init_scopes(symbol_table, container_scope);
}
pub fn make_symbol(&self) -> ParameterSymbol {
ParameterSymbol::new(
&self.declared_name,
Some(self.declared_name_source_range.clone()),
self.scope_id.unwrap(),
)
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
self.type_use.resolve_names(symbol_table)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
self.type_use.check_names(symbol_table)
}
#[deprecated]
pub fn gather_types_into(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) {
let type_info = self.type_use.type_info(symbol_table, types_table).clone();
let parameter_symbol = symbol_table
.get_parameter_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
.unwrap();
types_table
.parameter_types_mut()
.insert(parameter_symbol, type_info);
}
pub fn declared_type(&self, names_table: &NodesToSymbols) -> (TypeInfo, Diagnostics) {
self.type_use.declared_type(names_table)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
self.type_use.type_check(symbol_table, types_table)?;
Ok(())
}
} }

View File

@ -1,233 +1,9 @@
use crate::ast::assign_statement::AssignStatement; use crate::ast::assign_statement::AssignStatement;
use crate::ast::expression_statement::ExpressionStatement; use crate::ast::expression_statement::ExpressionStatement;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::let_statement::LetStatement; use crate::ast::let_statement::LetStatement;
use crate::ast::{NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use std::collections::HashSet;
use std::rc::Rc;
pub enum Statement { pub enum Statement {
Let(LetStatement), Let(LetStatement),
Expression(ExpressionStatement), Expression(ExpressionStatement),
Assign(AssignStatement), Assign(AssignStatement),
} }
impl Statement {
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
match self {
Statement::Let(let_statement) => {
let_statement.init_scopes(symbol_table, container_scope);
}
Statement::Expression(expression_statement) => {
expression_statement.init_scopes(symbol_table, container_scope);
}
Statement::Assign(assign_statement) => {
assign_statement.init_scopes(symbol_table, container_scope);
}
}
}
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
match self {
Statement::Let(let_statement) => let_statement.resolve_names_static(symbol_table),
Statement::Expression(expression_statement) => {
expression_statement.resolve_names_static(symbol_table)
}
Statement::Assign(assign_statement) => {
assign_statement.resolve_names_static(symbol_table)
}
}
}
pub fn resolve_names_ctor(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NodesToSymbols, Diagnostics) {
match self {
Statement::Let(let_statement) => {
let_statement.resolve_names_ctor(symbol_table, self_class_symbol)
}
Statement::Expression(expression_statement) => {
expression_statement.resolve_names_ctor(symbol_table, self_class_symbol)
}
Statement::Assign(assign_statement) => assign_statement.resolve_names_ctor(
symbol_table,
self_class_symbol,
initialized_fields,
),
}
}
pub fn resolve_names_method(
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NodesToSymbols, Diagnostics) {
match self {
Statement::Let(let_statement) => {
let_statement.resolve_names_method(symbol_table, self_class_symbol)
}
Statement::Expression(expression_statement) => {
expression_statement.resolve_names_method(symbol_table, self_class_symbol)
}
Statement::Assign(assign_statement) => {
assign_statement.resolve_names_method(symbol_table, self_class_symbol)
}
}
}
#[deprecated]
pub fn analyze_constructor_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Statement::Let(let_statement) => {
let_statement.analyze_constructor_local_names(symbol_table, class_symbol)
}
Statement::Expression(expression_statement) => {
expression_statement.check_constructor_local_names(symbol_table, class_symbol)
}
Statement::Assign(assign_statement) => {
assign_statement.check_constructor_local_names(symbol_table, class_symbol)
}
}
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
class_symbol: &ClassSymbol,
) -> Vec<Diagnostic> {
match self {
Statement::Let(let_statement) => {
let_statement.analyze_method_local_names(symbol_table, class_symbol)
}
Statement::Expression(expression_statement) => {
expression_statement.check_method_local_names(symbol_table, class_symbol)
}
Statement::Assign(assign_statement) => {
assign_statement.check_method_local_names(symbol_table, class_symbol)
}
}
}
#[deprecated]
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
match self {
Statement::Let(let_statement) => {
let_statement.analyze_static_fn_local_names(symbol_table)
}
Statement::Expression(expression_statement) => {
expression_statement.check_static_fn_local_names(symbol_table)
}
Statement::Assign(assign_statement) => {
assign_statement.check_static_fn_local_names(symbol_table)
}
}
}
pub fn resolve_types(
&self,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
) -> (SymbolsToTypes, NodesToTypes, Diagnostics) {
match self {
Statement::Let(let_statement) => {
let_statement.resolve_types(nodes_to_symbols, symbols_to_types)
}
Statement::Expression(expression_statement) => {
let (nts, ds) =
expression_statement.resolve_types(nodes_to_symbols, symbols_to_types);
(SymbolsToTypes::new(), nts, ds)
}
Statement::Assign(assign_statement) => {
let (nts, ds) = assign_statement.resolve_types(nodes_to_symbols, symbols_to_types);
(SymbolsToTypes::new(), nts, ds)
}
}
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
must_return_type_info: Option<&TypeInfo>,
) -> Result<(), Vec<Diagnostic>> {
match self {
Statement::Let(let_statement) => let_statement.type_check(symbol_table, types_table),
Statement::Expression(expression_statement) => {
expression_statement.type_check(symbol_table, types_table, must_return_type_info)
}
Statement::Assign(assign_statement) => {
assign_statement.type_check(symbol_table, types_table)
}
}
}
#[deprecated]
pub fn to_ir(
&self,
builder: &mut IrBuilder,
symbol_table: &SymbolTable,
types_table: &TypesTable,
should_return_value: bool,
) {
match self {
Statement::Let(let_statement) => {
let_statement.to_ir(builder, symbol_table, types_table);
}
Statement::Expression(expression_statement) => {
expression_statement.to_ir(builder, symbol_table, types_table, should_return_value);
}
Statement::Assign(assign_statement) => {
assign_statement.to_ir(builder, symbol_table, types_table);
}
}
}
pub fn lower_to_ir(
&self,
builder: &mut IrBuilder,
nodes_to_symbols: &NodesToSymbols,
symbols_to_types: &SymbolsToTypes,
nodes_to_types: &NodesToTypes,
is_return_statement: bool,
) {
match self {
Statement::Let(let_statement) => {
let_statement.lower(builder, nodes_to_symbols, symbols_to_types, nodes_to_types);
}
Statement::Expression(expression_statement) => {
expression_statement.lower_to_ir(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
is_return_statement,
);
}
Statement::Assign(assign_statement) => {
assign_statement.lower_to_ir(
builder,
nodes_to_symbols,
symbols_to_types,
nodes_to_types,
);
}
}
}
}

View File

@ -1,14 +1,5 @@
use crate::ast::{NodeId, NodesToSymbols}; use crate::ast::NodeId;
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::{cannot_provide_generic_args_generic_type, symbol_not_found};
use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::type_symbol::TypeSymbol;
use crate::symbol_table::SymbolTable;
use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics};
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
pub struct TypeUse { pub struct TypeUse {
@ -16,7 +7,6 @@ pub struct TypeUse {
declared_name: Rc<str>, declared_name: Rc<str>,
declared_name_source_range: SourceRange, declared_name_source_range: SourceRange,
generic_arguments: Vec<TypeUse>, generic_arguments: Vec<TypeUse>,
scope_id: Option<usize>,
} }
impl TypeUse { impl TypeUse {
@ -31,7 +21,6 @@ impl TypeUse {
declared_name: declared_name.into(), declared_name: declared_name.into(),
declared_name_source_range, declared_name_source_range,
generic_arguments, generic_arguments,
scope_id: None,
} }
} }
@ -42,236 +31,4 @@ impl TypeUse {
pub fn node_id(&self) -> NodeId { pub fn node_id(&self) -> NodeId {
self.node_id self.node_id
} }
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
self.scope_id = Some(container_scope);
for type_use in &mut self.generic_arguments {
type_use.init_scopes(symbol_table, container_scope);
}
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Vec::new();
let mut resolved_names = HashMap::new();
// resolve this name
match symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name) {
None => {
diagnostics.push(symbol_not_found(
&self.declared_name,
&self.declared_name_source_range,
));
}
Some(type_symbol) => {
resolved_names.insert(self.node_id, type_symbol.into_symbol());
}
}
// check generic args
for type_use in &self.generic_arguments {
let (ns, mut ds) = type_use.resolve_names(symbol_table);
for (node_id, symbol) in ns {
resolved_names.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
(resolved_names, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
// find this name
let maybe_type_symbol =
symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name);
if maybe_type_symbol.is_none() {
diagnostics.push(symbol_not_found(
self.declared_name(),
&self.declared_name_source_range,
));
}
// check generic args
for type_use in &self.generic_arguments {
diagnostics.append(&mut type_use.check_names(symbol_table));
}
diagnostics
}
#[deprecated]
pub fn gather_types(
&self,
symbol_table: &SymbolTable,
types_table: &mut TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics = Vec::new();
for type_use in &self.generic_arguments {
handle_diagnostics!(
type_use.gather_types(symbol_table, types_table),
diagnostics
);
}
diagnostics_result!(diagnostics)
}
pub fn declared_type(&self, names_table: &NodesToSymbols) -> (TypeInfo, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut generic_argument_type_infos = Vec::new();
for type_use in &self.generic_arguments {
let (type_info, mut ds) = type_use.declared_type(names_table);
generic_argument_type_infos.push(type_info);
diagnostics.append(&mut ds);
}
let base_type_symbol = names_table.get(&self.node_id).unwrap().unwrap_type_symbol();
match base_type_symbol {
TypeSymbol::Class(class_symbol) => (
TypeInfo::ParameterizedClass(class_symbol, generic_argument_type_infos),
diagnostics,
),
TypeSymbol::GenericParameter(generic_parameter_symbol) => {
if generic_argument_type_infos.is_empty() {
(TypeInfo::GenericType(generic_parameter_symbol), diagnostics)
} else {
diagnostics.push(cannot_provide_generic_args_generic_type(
&self.declared_name_source_range,
));
(TypeInfo::PlaceholderError, diagnostics)
}
}
}
}
pub fn type_info<'a>(
&self,
symbol_table: &SymbolTable,
types_table: &'a TypesTable,
) -> &'a TypeInfo {
let type_symbol = symbol_table
.find_type_symbol(self.scope_id.unwrap(), self.declared_name())
.unwrap();
match type_symbol {
TypeSymbol::Class(class_symbol) => {
types_table
.class_types()
.get(&class_symbol)
.expect(&format!(
"Could not get TypeInfo for {}",
self.declared_name
))
}
TypeSymbol::GenericParameter(generic_parameter_symbol) => types_table
.generic_parameter_types()
.get(&generic_parameter_symbol)
.expect(&format!(
"Could not get TypeInfo for {}",
self.declared_name
)),
}
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
types_table: &TypesTable,
) -> Result<(), Vec<Diagnostic>> {
let mut diagnostics: Vec<Diagnostic> = vec![];
match self.type_info(symbol_table, types_table) {
TypeInfo::Class(class_symbol) => {
// check number of params/args match
let generic_parameters = class_symbol.generic_parameters();
if generic_parameters.len() != self.generic_arguments.len() {
let diagnostic = Diagnostic::new(
&format!(
"Expected {} generic arguments; found {}.",
generic_parameters.len(),
self.generic_arguments.len()
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
)
.with_reporter(file!(), line!())
.with_error_code(INCORRECT_GENERIC_ARGUMENTS);
diagnostics.push(diagnostic);
}
maybe_return_diagnostics!(diagnostics);
// check that each arg is assignable to the param's extends
// for i in 0..self.generic_arguments.len() {
// let generic_parameter_symbol = &generic_parameters[i];
// if generic_parameter_symbol.extends().len() > 0 {
// unimplemented!("Generic extends not implemented yet.")
// }
// }
}
_ => {
// cannot extend a non-class type (except for Any)
if self.generic_arguments.len() > 0 {
let diagnostic = Diagnostic::new(
&format!(
"Type {} does not accept generic arguments.",
self.type_info(symbol_table, types_table)
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
)
.with_reporter(file!(), line!())
.with_error_code(INCORRECT_GENERIC_ARGUMENTS);
diagnostics.push(diagnostic);
}
}
}
// recurse on generic arguments
for generic_argument in &mut self.generic_arguments {
handle_diagnostics!(
generic_argument.type_check(symbol_table, types_table),
diagnostics
);
}
diagnostics_result!(diagnostics)
}
}
#[cfg(test)]
mod tests {
use crate::diagnostic::Diagnostic;
use crate::parser::get_compilation_unit;
use crate::symbol_table::SymbolTable;
use crate::types_table::TypesTable;
#[test]
fn type_check_generics() -> Result<(), Vec<Diagnostic>> {
let mut compilation_unit = get_compilation_unit(
"
class String end
class Foo<T>
ctor(t: T) end
end
fn useFoo(foo: Foo<String>) end
",
None,
)?;
let mut symbol_table = SymbolTable::new();
let mut types_table = TypesTable::new();
compilation_unit.init_scopes(&mut symbol_table);
compilation_unit.gather_symbols_into(&mut symbol_table)?;
compilation_unit.check_names(&mut symbol_table)?;
compilation_unit.gather_types_into(&symbol_table, &mut types_table)?;
compilation_unit.type_check(&mut symbol_table, &mut types_table)?;
Ok(())
}
} }

View File

@ -1,146 +0,0 @@
use crate::ast::compilation_unit::CompilationUnit;
use crate::diagnostic::Diagnostics;
use crate::ir::ir_class::IrClass;
use crate::ir::ir_function::IrFunction;
use crate::parser::parse_compilation_unit;
use crate::symbol_table::SymbolTable;
use crate::symbol_table::util::try_insert_symbols_into;
use std::collections::HashMap;
use std::rc::Rc;
pub type Filename = Rc<str>;
pub type FileId = usize;
fn parse_compilation_units(
inputs: &HashMap<FileId, &str>,
) -> Result<HashMap<FileId, CompilationUnit>, Diagnostics> {
let mut parse_diagnostics = Vec::new();
let mut compilation_units = HashMap::new();
for (file_id, source) in inputs {
let (compilation_unit, mut ds) = parse_compilation_unit(source, Some(*file_id));
parse_diagnostics.append(&mut ds);
compilation_units.insert(*file_id, compilation_unit);
}
if parse_diagnostics.is_empty() {
Ok(compilation_units)
} else {
Err(parse_diagnostics)
}
}
pub fn compile_compilation_units(
inputs: &HashMap<FileId, &str>,
symbol_table: &mut SymbolTable,
) -> Result<(Vec<IrClass>, Vec<IrFunction>), Diagnostics> {
let mut compilation_units = parse_compilation_units(inputs)?;
// init scopes
for compilation_unit in compilation_units.values_mut() {
compilation_unit.init_scopes(symbol_table);
}
// gather unordered symbols
let all_symbols = compilation_units
.values()
.flat_map(|compilation_unit| compilation_unit.declared_symbols())
.collect::<Vec<_>>();
try_insert_symbols_into(all_symbols, symbol_table)?;
// now we can just finish each compilation unit, since we have the symbols
let mut ir_classes = Vec::new();
let mut ir_functions = Vec::new();
let mut diagnostics = Vec::new();
for compilation_unit in compilation_units.values() {
let (nodes_to_symbols, mut ds) = compilation_unit.resolve_names(symbol_table);
// in the future, we'll ideally be able to *actually* continue with the following steps
// instead of aborting here, but this needs to be tested :)
if !ds.is_empty() {
diagnostics.append(&mut ds);
continue;
}
let (mut symbols_to_types, mut ds) = compilation_unit.declared_types(&nodes_to_symbols);
if !ds.is_empty() {
diagnostics.append(&mut ds);
continue;
}
let (sts, nodes_to_types, mut ds) =
compilation_unit.resolve_types(&nodes_to_symbols, &symbols_to_types);
if !ds.is_empty() {
diagnostics.append(&mut ds);
continue;
}
// merge
for (symbol, type_info) in sts {
symbols_to_types.insert(symbol, type_info);
}
let (mut classes, mut functions) =
compilation_unit.lower_to_ir(&nodes_to_symbols, &symbols_to_types, &nodes_to_types);
ir_classes.append(&mut classes);
ir_functions.append(&mut functions);
}
if diagnostics.is_empty() {
Ok((ir_classes, ir_functions))
} else {
Err(diagnostics)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::symbol::class_symbol::ClassSymbol;
fn prepare_symbol_table(symbol_table: &mut SymbolTable) {
let global_scope = symbol_table.push_module_scope("global scope");
let any_symbol = ClassSymbol::new(
&"Any".into(),
None,
vec!["Any".into()],
false,
global_scope,
Vec::new(),
None,
Vec::new(),
Vec::new(),
);
symbol_table.insert_class_symbol(Rc::new(any_symbol));
let void_symbol = ClassSymbol::new(
&"Void".into(),
None,
vec!["Void".into()],
false,
global_scope,
Vec::new(),
None,
Vec::new(),
Vec::new(),
);
symbol_table.insert_class_symbol(Rc::new(void_symbol));
}
#[test]
fn hello_world() -> Result<(), Diagnostics> {
let input = "
extern fn println(msg: Any) -> Void
fn main()
println(\"Hello, World!\")
end
";
let mut inputs = HashMap::new();
inputs.insert(0, input);
let mut symbol_table = SymbolTable::new();
prepare_symbol_table(&mut symbol_table);
let (ir_classes, ir_functions) = compile_compilation_units(&inputs, &mut symbol_table)?;
assert_eq!(ir_classes.len(), 0);
assert_eq!(ir_functions.len(), 1);
Ok(())
}
}

View File

@ -1,4 +1,4 @@
use crate::ast::fqn_util::fqn_parts_to_string; use crate::fqn_util::fqn_parts_to_string;
use crate::type_info::TypeInfo; use crate::type_info::TypeInfo;
use dvm_lib::vm::class::{Class, Field}; use dvm_lib::vm::class::{Class, Field};
use dvm_lib::vm::type_info::TypeInfo as VmTypeInfo; use dvm_lib::vm::type_info::TypeInfo as VmTypeInfo;

View File

@ -14,11 +14,11 @@ use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
pub mod ast; pub mod ast;
pub mod compile_pipeline;
pub mod constants_table; pub mod constants_table;
pub mod diagnostic; pub mod diagnostic;
mod diagnostic_factories; mod diagnostic_factories;
pub mod error_codes; pub mod error_codes;
pub mod fqn_util;
pub mod intrinsics; pub mod intrinsics;
pub mod ir; pub mod ir;
pub mod lexer; pub mod lexer;

View File

@ -1,3 +1,4 @@
use crate::FileId;
use crate::ast::assign_statement::AssignStatement; use crate::ast::assign_statement::AssignStatement;
use crate::ast::binary_expression::{BinaryExpression, BinaryOperation}; use crate::ast::binary_expression::{BinaryExpression, BinaryOperation};
use crate::ast::call::Call; use crate::ast::call::Call;
@ -19,7 +20,6 @@ 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::type_use::TypeUse; use crate::ast::type_use::TypeUse;
use crate::compile_pipeline::FileId;
use crate::diagnostic::{Diagnostic, Diagnostics}; use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::error_codes::{LEXER_ERROR, PARSE_ERROR}; use crate::error_codes::{LEXER_ERROR, PARSE_ERROR};
use crate::lexer::{Lexer, LexerErrorKind}; use crate::lexer::{Lexer, LexerErrorKind};
@ -988,7 +988,7 @@ impl<'a> Parser<'a> {
(Statement::Assign(assign_statement), diagnostics) (Statement::Assign(assign_statement), diagnostics)
} else { } else {
( (
Statement::Expression(ExpressionStatement::new(self.next_node_id(), base)), Statement::Expression(ExpressionStatement::new(base)),
diagnostics, diagnostics,
) )
} }

View File

@ -1,4 +1,4 @@
use crate::ast::fqn_util::fqn_parts_to_string; use crate::fqn_util::fqn_parts_to_string;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::constructor_symbol::ConstructorSymbol; use crate::symbol::constructor_symbol::ConstructorSymbol;
use crate::symbol::field_symbol::FieldSymbol; use crate::symbol::field_symbol::FieldSymbol;

View File

@ -1,4 +1,4 @@
use crate::ast::fqn_util::fqn_parts_to_string; use crate::fqn_util::fqn_parts_to_string;
use crate::source_range::SourceRange; use crate::source_range::SourceRange;
use crate::symbol::parameter_symbol::ParameterSymbol; use crate::symbol::parameter_symbol::ParameterSymbol;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};