Work on new compile pipeline and semantic analysis flow WIP.

This commit is contained in:
Jesse Brault 2026-04-12 17:24:37 -05:00
parent 96ea0c5e50
commit 4ae4f7e9e6
31 changed files with 1228 additions and 153 deletions

View File

@ -1,13 +1,17 @@
use crate::ast::NamesTable;
use crate::ast::expression::Expression;
use crate::ast::helpers::insert_resolved_names_into;
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::class_symbol::ClassSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol_table::SymbolTable;
@ -37,9 +41,12 @@ impl AssignStatement {
self.value.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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);
@ -57,9 +64,9 @@ impl AssignStatement {
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
@ -84,6 +91,24 @@ impl AssignStatement {
(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,
@ -100,6 +125,7 @@ impl AssignStatement {
.collect()
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -116,6 +142,7 @@ impl AssignStatement {
.collect()
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
[
self.destination.check_static_fn_local_names(symbol_table),
@ -126,6 +153,79 @@ impl AssignStatement {
.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)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,

View File

@ -1,7 +1,7 @@
use crate::ast::NamesTable;
use crate::ast::expression::Expression;
use crate::ast::helpers::insert_resolved_names_into;
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;
@ -33,6 +33,7 @@ pub enum BinaryOperation {
}
pub struct BinaryExpression {
node_id: NodeId,
lhs: Box<Expression>,
rhs: Box<Expression>,
op: BinaryOperation,
@ -42,12 +43,14 @@ pub struct BinaryExpression {
impl BinaryExpression {
pub fn new(
node_id: NodeId,
lhs: Expression,
rhs: Expression,
op: BinaryOperation,
source_range: SourceRange,
) -> Self {
Self {
node_id,
lhs: lhs.into(),
rhs: rhs.into(),
op,
@ -56,6 +59,10 @@ impl BinaryExpression {
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn lhs(&self) -> &Expression {
&self.lhs
}
@ -81,9 +88,12 @@ impl BinaryExpression {
self.rhs.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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);
@ -98,9 +108,9 @@ impl BinaryExpression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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);
@ -115,9 +125,9 @@ impl BinaryExpression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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);
@ -128,6 +138,24 @@ impl BinaryExpression {
(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,
@ -144,6 +172,7 @@ impl BinaryExpression {
.collect()
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
@ -160,6 +189,7 @@ impl BinaryExpression {
.collect()
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -176,6 +206,7 @@ impl BinaryExpression {
.collect()
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
[
self.lhs.check_static_fn_local_names(symbol_table),
@ -186,6 +217,124 @@ impl BinaryExpression {
.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,

View File

@ -1,13 +1,16 @@
use crate::ast::NamesTable;
use crate::ast::expression::Expression;
use crate::ast::fqn_util::fqn_parts_to_string;
use crate::ast::helpers::insert_resolved_names_into;
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;
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::symbol::Symbol;
use crate::symbol::callable_symbol::CallableSymbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
@ -16,20 +19,31 @@ use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
pub struct Call {
node_id: NodeId,
callee: Box<Expression>,
arguments: Vec<Expression>,
source_range: SourceRange,
}
impl Call {
pub fn new(callee: Expression, arguments: Vec<Expression>, source_range: SourceRange) -> Self {
pub fn new(
node_id: NodeId,
callee: Expression,
arguments: Vec<Expression>,
source_range: SourceRange,
) -> Self {
Self {
node_id,
callee: callee.into(),
arguments,
source_range,
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn callee(&self) -> &Expression {
&self.callee
}
@ -45,9 +59,12 @@ impl Call {
}
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self.callee.resolve_names_static(symbol_table);
@ -68,9 +85,9 @@ impl Call {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
@ -93,9 +110,9 @@ impl Call {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
{
let (ns, mut ds) = self
@ -114,6 +131,32 @@ impl Call {
(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,
@ -132,6 +175,7 @@ impl Call {
diagnostics
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
@ -150,6 +194,7 @@ impl Call {
diagnostics
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -167,6 +212,7 @@ impl Call {
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 {
@ -176,6 +222,88 @@ impl Call {
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)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
@ -303,6 +431,7 @@ impl Call {
.constructor_return_types()
.get(&constructor_symbol)
.unwrap(),
CallableSymbol::ErrorPlaceholder => unreachable!(),
}
}
@ -335,6 +464,7 @@ impl Call {
arguments,
false,
),
CallableSymbol::ErrorPlaceholder => unreachable!(),
}
}

View File

@ -11,7 +11,7 @@ use crate::ast::helpers::{
resolve_ctor_name,
};
use crate::ast::statement::Statement;
use crate::ast::{NamesTable, NodeId};
use crate::ast::{NodeId, NodesToSymbols};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT};
use crate::ir::ir_class::{IrClass, IrField};
@ -94,7 +94,7 @@ impl Class {
symbol_table.pop_scope();
}
pub fn make_symbols(&self, fqn_context: &FqnContext) -> Vec<Symbol> {
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();
@ -133,7 +133,7 @@ impl Class {
let mut function_symbols = Vec::new();
for function in &self.functions {
let (function_symbol, mut symbols) =
function.make_symbols(&class_body_fqn_context, true);
function.declared_symbols(&class_body_fqn_context, true);
all_symbols.append(&mut symbols);
function_symbols.push(function_symbol);
}
@ -154,9 +154,9 @@ impl Class {
all_symbols
}
pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
for generic_parameter in &self.generic_parameters {
let (ns, mut ds) = generic_parameter.resolve_names(symbol_table);

View File

@ -2,15 +2,17 @@ use crate::ast::class::Class;
use crate::ast::extern_function::ExternFunction;
use crate::ast::fqn_context::FqnContext;
use crate::ast::function::Function;
use crate::ast::helpers::{collect_diagnostics_into_mut, insert_resolved_types_into};
use crate::ast::{NamesTable, ResolvedTypes};
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::util::try_insert_symbols_into;
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};
@ -62,20 +64,20 @@ impl CompilationUnit {
symbol_table.pop_scope();
}
pub fn gather_unordered_symbols(&self) -> Vec<Symbol> {
pub fn declared_symbols(&self) -> Vec<Symbol> {
let fqn_context = FqnContext::new();
[
self.classes
.iter()
.flat_map(|class| class.make_symbols(&fqn_context))
.flat_map(|class| class.declared_symbols(&fqn_context))
.collect::<Vec<_>>(),
self.extern_functions
.iter()
.flat_map(|function| function.make_symbols(&fqn_context).1)
.flat_map(|function| function.declared_symbols(&fqn_context).1)
.collect(),
self.functions
.iter()
.flat_map(|function| function.make_symbols(&fqn_context, false).1)
.flat_map(|function| function.declared_symbols(&fqn_context, false).1)
.collect(),
]
.into_iter()
@ -92,24 +94,24 @@ impl CompilationUnit {
let fqn_context = FqnContext::new();
for class in &self.classes {
handle_diagnostics!(
try_insert_symbols_into(class.make_symbols(&fqn_context), symbol_table),
try_insert_symbols_into(class.declared_symbols(&fqn_context), symbol_table),
diagnostics
);
}
for function in &self.functions {
let (_, symbols) = function.make_symbols(&fqn_context, false);
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.make_symbols(&fqn_context);
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) -> (NamesTable, Diagnostics) {
pub fn resolve_names(&self, symbol_table: &mut SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
for function in &self.functions {
let (ns, mut ds) = function.resolve_names_static(symbol_table);
@ -156,19 +158,41 @@ impl CompilationUnit {
diagnostics_result!(diagnostics)
}
pub fn resolve_types(&self, names_table: &NamesTable) -> (ResolvedTypes, Diagnostics) {
/// Associate each declared symbol with a TypeInfo.
pub fn declared_types(&self, names_table: &NodesToSymbols) -> (SymbolsToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut resolved_types = ResolvedTypes::new();
let mut declared_types = SymbolsToTypes::new();
for function in &self.functions {
let (ts, mut ds) = todo!();
insert_resolved_types_into(ts, &mut resolved_types);
let (dts, mut ds) = function.declared_types(names_table);
insert_declared_types_into(dts, &mut declared_types);
diagnostics.append(&mut ds);
}
(resolved_types, diagnostics)
(declared_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,
@ -192,6 +216,7 @@ impl CompilationUnit {
diagnostics_result!(diagnostics)
}
#[deprecated]
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,
@ -220,6 +245,10 @@ impl CompilationUnit {
diagnostics_result!(diagnostics)
}
pub fn lower(&self, resolved_types: &NodesToTypes) -> (Vec<IrClass>, Vec<IrFunction>) {
todo!()
}
pub fn to_ir(
&self,
symbol_table: &SymbolTable,

View File

@ -1,4 +1,4 @@
use crate::ast::NamesTable;
use crate::ast::NodesToSymbols;
use crate::ast::field::Field;
use crate::ast::fqn_context::FqnContext;
use crate::ast::fqn_util::fqn_parts_to_string;
@ -103,9 +103,9 @@ impl Constructor {
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
for parameter in &self.parameters {
let (ns, mut ds) = parameter.resolve_names(symbol_table);

View File

@ -1,22 +1,29 @@
use crate::ast::NodeId;
use crate::source_range::SourceRange;
use crate::type_info::TypeInfo;
pub struct DoubleLiteral {
node_id: NodeId,
value: f64,
source_range: SourceRange,
type_info: &'static TypeInfo,
}
impl DoubleLiteral {
pub fn new(value: f64, source_range: SourceRange) -> Self {
pub fn new(node_id: NodeId, value: f64, source_range: SourceRange) -> Self {
const TYPE_INFO: TypeInfo = TypeInfo::Double;
Self {
node_id,
value,
source_range,
type_info: &TYPE_INFO,
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn value(&self) -> f64 {
self.value
}

View File

@ -1,4 +1,3 @@
use crate::ast::NamesTable;
use crate::ast::binary_expression::BinaryExpression;
use crate::ast::call::Call;
use crate::ast::double_literal::DoubleLiteral;
@ -7,6 +6,7 @@ use crate::ast::integer_literal::IntegerLiteral;
use crate::ast::ir_builder::IrBuilder;
use crate::ast::negative_expression::NegativeExpression;
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;
@ -32,6 +32,18 @@ pub enum Expression {
}
impl Expression {
pub fn node_id(&self) -> NodeId {
match self {
Expression::Binary(binary_expression) => binary_expression.node_id(),
Expression::Negative(negative_expression) => negative_expression.node_id(),
Expression::Call(call) => call.node_id(),
Expression::Identifier(identifier) => identifier.node_id(),
Expression::Integer(integer_literal) => integer_literal.node_id(),
Expression::Double(double_literal) => double_literal.node_id(),
Expression::String(string_literal) => string_literal.node_id(),
}
}
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
match self {
Expression::Binary(binary_expression) => {
@ -50,7 +62,10 @@ impl Expression {
}
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_static(symbol_table)
@ -60,7 +75,7 @@ impl Expression {
}
Expression::Call(call) => call.resolve_names_static(symbol_table),
Expression::Identifier(identifier) => identifier.resolve_name_static(symbol_table),
_ => (NamesTable::new(), Diagnostics::new()),
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
@ -68,7 +83,7 @@ impl Expression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_field_init(symbol_table, self_class_symbol)
@ -82,7 +97,7 @@ impl Expression {
Expression::Identifier(identifier) => {
identifier.resolve_name_field_init(symbol_table, self_class_symbol)
}
_ => (NamesTable::new(), Diagnostics::new()),
_ => (NodesToSymbols::new(), Diagnostics::new()),
}
}
@ -90,7 +105,7 @@ impl Expression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
match self {
Expression::Binary(binary_expression) => {
binary_expression.resolve_names_ctor(symbol_table, self_class_symbol)
@ -102,10 +117,31 @@ impl Expression {
Expression::Identifier(identifier) => {
identifier.resolve_name_ctor(symbol_table, self_class_symbol)
}
_ => (NamesTable::new(), Diagnostics::new()),
_ => (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,
@ -134,6 +170,7 @@ impl Expression {
}
}
#[deprecated]
pub fn check_constructor_destination_names(
&self,
symbol_table: &SymbolTable,
@ -162,6 +199,7 @@ impl Expression {
}
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
@ -190,6 +228,7 @@ impl Expression {
}
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -216,6 +255,7 @@ impl Expression {
}
}
#[deprecated]
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
match self {
Expression::Binary(binary_expression) => {
@ -244,6 +284,43 @@ impl Expression {
}
}
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())
}
}
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,

View File

@ -1,6 +1,6 @@
use crate::ast::NamesTable;
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;
@ -10,12 +10,14 @@ use crate::type_info::TypeInfo;
use crate::types_table::TypesTable;
pub struct ExpressionStatement {
node_id: NodeId,
expression: Box<Expression>,
}
impl ExpressionStatement {
pub fn new(expression: Expression) -> Self {
pub fn new(node_id: NodeId, expression: Expression) -> Self {
Self {
node_id,
expression: expression.into(),
}
}
@ -28,7 +30,10 @@ impl ExpressionStatement {
self.expression.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
self.expression.resolve_names_static(symbol_table)
}
@ -36,11 +41,21 @@ impl ExpressionStatement {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (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,
@ -50,6 +65,7 @@ impl ExpressionStatement {
.check_constructor_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -59,10 +75,30 @@ impl ExpressionStatement {
.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,

View File

@ -4,7 +4,7 @@ use crate::ast::helpers::{
};
use crate::ast::parameter::Parameter;
use crate::ast::type_use::TypeUse;
use crate::ast::{NamesTable, NodeId};
use crate::ast::{NodeId, NodesToSymbols};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
@ -60,7 +60,7 @@ impl ExternFunction {
symbol_table.pop_scope();
}
pub fn make_symbols(&self, fqn_context: &FqnContext) -> (Rc<FunctionSymbol>, Vec<Symbol>) {
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();
@ -80,9 +80,12 @@ impl ExternFunction {
(function_symbol, all_symbols)
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
resolve_parameter_names_into(
&self.parameters,

View File

@ -1,4 +1,4 @@
use crate::ast::NamesTable;
use crate::ast::NodesToSymbols;
use crate::ast::expression::Expression;
use crate::ast::helpers::insert_resolved_names_into;
use crate::ast::type_use::TypeUse;
@ -85,8 +85,8 @@ impl Field {
&self,
symbol_table: &SymbolTable,
class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
let mut names_table = NamesTable::new();
) -> (NodesToSymbols, Diagnostics) {
let mut names_table = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
if let Some(type_use) = &self.declared_type {

View File

@ -2,13 +2,14 @@ use crate::ast::fqn_context::FqnContext;
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, resolve_parameter_names_into,
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::statement::Statement;
use crate::ast::type_use::TypeUse;
use crate::ast::{NamesTable, NodeId};
use crate::ast::{NodeId, NodesToSymbols, NodesToTypes, SymbolsToTypes};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::ir::ir_function::IrFunction;
use crate::ir::ir_parameter::IrParameter;
@ -57,6 +58,10 @@ impl Function {
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn declared_name(&self) -> &str {
&self.declared_name
}
@ -88,7 +93,8 @@ impl Function {
symbol_table.pop_scope(); // function
}
pub fn make_symbols(
/// Return value contains self FunctionSymbol followed by all symbols (including self symbol).
pub fn declared_symbols(
&self,
fqn_context: &FqnContext,
is_method: bool,
@ -112,51 +118,58 @@ impl Function {
(function_symbol, all_symbols)
}
fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
fn resolve_names_common(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut nodes_to_symbols = NodesToSymbols::new();
resolve_parameter_names_into(
&self.parameters,
symbol_table,
&mut names_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);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
(nodes_to_symbols, diagnostics)
}
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NamesTable, Diagnostics) {
let (mut names_table, mut diagnostics) = self.resolve_names_common(symbol_table);
) -> (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);
for (node_id, symbol) in ns {
names_table.insert(node_id, symbol);
}
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
(names_table, diagnostics)
(nodes_to_symbols, diagnostics)
}
pub fn resolve_names_method(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
let (names_table, diagnostics) = self.resolve_names_common(symbol_table);
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);
(names_table, diagnostics)
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 {
@ -168,6 +181,7 @@ impl Function {
diagnostics
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
@ -179,6 +193,7 @@ impl Function {
.collect()
}
#[deprecated]
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
self.statements
.iter()
@ -186,6 +201,41 @@ impl Function {
.collect()
}
pub fn declared_types(&self, names_table: &NodesToSymbols) -> (SymbolsToTypes, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut declared_types = SymbolsToTypes::new();
for parameter in &self.parameters {
let symbol = names_table.get(&parameter.node_id()).unwrap();
let (type_info, mut ds) = parameter.declared_type(names_table);
declared_types.insert(symbol.clone(), type_info);
diagnostics.append(&mut ds);
}
(declared_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)
}
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())

View File

@ -1,4 +1,4 @@
use crate::ast::NamesTable;
use crate::ast::NodesToSymbols;
use crate::ast::helpers::insert_resolved_names_into;
use crate::ast::type_use::TypeUse;
use crate::diagnostic::{Diagnostic, Diagnostics};
@ -49,9 +49,9 @@ impl GenericParameter {
)
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
for type_use in &self.extends {
let (ns, mut ds) = type_use.resolve_names(symbol_table);

View File

@ -1,6 +1,6 @@
use crate::ast::{NamesTable, ResolvedTypes};
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;
@ -110,25 +110,31 @@ pub fn collect_parameter_symbols_into(
pub fn resolve_parameter_names_into(
parameters: &[Parameter],
symbol_table: &SymbolTable,
names_table: &mut NamesTable,
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 {
names_table.insert(node_id, symbol);
nodes_to_symbols.insert(node_id, symbol);
}
diagnostics.append(&mut ds);
}
}
pub fn insert_resolved_names_into(source: NamesTable, destination: &mut NamesTable) {
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_resolved_types_into(source: ResolvedTypes, destination: &mut ResolvedTypes) {
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,6 +1,6 @@
use crate::ast::ir_builder::IrBuilder;
use crate::ast::ir_util::get_or_init_field_pointer_variable;
use crate::ast::{NamesTable, NodeId};
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,
@ -43,6 +43,10 @@ impl Identifier {
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn name(&self) -> &str {
&self.name
}
@ -55,9 +59,9 @@ impl Identifier {
self.scope_id.unwrap()
}
pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_name_static(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::new();
let mut names_table = NodesToSymbols::new();
match symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name) {
None => {
@ -75,9 +79,9 @@ impl Identifier {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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 {
@ -125,9 +129,9 @@ impl Identifier {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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 {
@ -173,9 +177,9 @@ impl Identifier {
&self,
symbol_table: &SymbolTable,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Diagnostics::new();
let mut names_table = NamesTable::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 {
@ -217,11 +221,33 @@ impl Identifier {
(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 NamesTable,
names_table: &mut NodesToSymbols,
diagnostics: &mut Diagnostics,
) {
// Check against recursively constructing this class.
@ -254,7 +280,7 @@ impl Identifier {
&self,
self_class_symbol: &ClassSymbol,
function_symbol: &Rc<FunctionSymbol>,
names_table: &mut NamesTable,
names_table: &mut NodesToSymbols,
diagnostics: &mut Diagnostics,
) {
if self_class_symbol
@ -356,6 +382,7 @@ impl Identifier {
}
}
#[deprecated]
pub fn check_constructor_destination_name(
&self,
symbol_table: &SymbolTable,
@ -390,6 +417,7 @@ impl Identifier {
}
}
#[deprecated]
pub fn check_constructor_local_name(
&self,
symbol_table: &SymbolTable,
@ -415,6 +443,7 @@ impl Identifier {
}
}
#[deprecated]
pub fn check_method_local_name(
&self,
symbol_table: &SymbolTable,
@ -462,6 +491,7 @@ impl Identifier {
}
/// 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)
@ -477,6 +507,20 @@ impl Identifier {
&self.source_range
}
pub fn resolve_type(
&self,
resolved_symbols: &NodesToSymbols,
resolved_symbol_type_infos: &SymbolsToTypes,
) -> (NodesToTypes, Diagnostics) {
let self_symbol = resolved_symbols.get(&self.node_id).unwrap();
let type_info = resolved_symbol_type_infos.get(self_symbol).unwrap();
let mut resolved_types = NodesToTypes::new();
resolved_types.insert(self.node_id, type_info.clone());
(resolved_types, Diagnostics::new())
}
pub fn type_info<'a>(
&self,
symbol_table: &SymbolTable,

View File

@ -1,16 +1,19 @@
use crate::ast::NodeId;
use crate::source_range::SourceRange;
use crate::type_info::TypeInfo;
pub struct IntegerLiteral {
node_id: NodeId,
value: i32,
source_range: SourceRange,
type_info: &'static TypeInfo,
}
impl IntegerLiteral {
pub fn new(value: i32, source_range: SourceRange) -> Self {
pub fn new(node_id: NodeId, value: i32, source_range: SourceRange) -> Self {
const TYPE_INFO: TypeInfo = TypeInfo::Integer;
Self {
node_id,
value,
source_range,
type_info: &TYPE_INFO,
@ -21,6 +24,10 @@ impl IntegerLiteral {
self.value
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn type_info(&self) -> &TypeInfo {
&self.type_info
}

View File

@ -1,7 +1,7 @@
use crate::ast::NamesTable;
use crate::ast::expression::Expression;
use crate::ast::helpers::insert_resolved_names_into;
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;
@ -18,6 +18,7 @@ use std::cell::RefCell;
use std::rc::Rc;
pub struct LetStatement {
node_id: NodeId,
declared_name: Rc<str>,
declared_name_source_range: SourceRange,
is_mut: bool,
@ -27,12 +28,14 @@ pub struct LetStatement {
impl LetStatement {
pub fn new(
node_id: NodeId,
declared_name: &str,
declared_name_source_range: SourceRange,
is_mut: bool,
initializer: Expression,
) -> Self {
Self {
node_id,
declared_name: declared_name.into(),
declared_name_source_range,
is_mut,
@ -78,8 +81,8 @@ impl LetStatement {
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NamesTable, Diagnostics) {
let mut names_table = NamesTable::new();
) -> (NodesToSymbols, Diagnostics) {
let mut names_table = NodesToSymbols::new();
let mut diagnostics = Diagnostics::new();
{
@ -99,15 +102,15 @@ impl LetStatement {
&self,
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
let mut names_table = NamesTable::new();
) -> (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 names_table);
insert_resolved_names_into(ns, &mut nodes_to_symbols);
diagnostics.append(&mut ds);
}
@ -115,9 +118,33 @@ impl LetStatement {
diagnostics.push(diagnostic);
}
(names_table, diagnostics)
(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);
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,
@ -136,6 +163,7 @@ impl LetStatement {
diagnostics
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
@ -153,6 +181,7 @@ impl LetStatement {
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));
@ -162,17 +191,29 @@ impl LetStatement {
diagnostics
}
pub fn gather_local_type(&self, symbol_table: &SymbolTable, types_table: &mut TypesTable) {
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);
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)
}
pub fn type_check(

View File

@ -1,6 +1,6 @@
use crate::symbol::Symbol;
use std::collections::HashMap;
use crate::type_info::TypeInfo;
use std::collections::HashMap;
pub mod assign_statement;
pub mod binary_expression;
@ -31,5 +31,6 @@ pub mod string_literal;
pub mod type_use;
pub type NodeId = usize;
pub type NamesTable = HashMap<NodeId, Symbol>;
pub type ResolvedTypes = HashMap<NodeId, TypeInfo>;
pub type NodesToSymbols = HashMap<NodeId, Symbol>;
pub type SymbolsToTypes = HashMap<Symbol, TypeInfo>;
pub type NodesToTypes = HashMap<NodeId, TypeInfo>;

View File

@ -1,7 +1,8 @@
use crate::ast::NamesTable;
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;
@ -17,20 +18,26 @@ use std::cell::RefCell;
use std::rc::Rc;
pub struct NegativeExpression {
node_id: NodeId,
operand: Box<Expression>,
source_range: SourceRange,
type_info: Option<TypeInfo>,
}
impl NegativeExpression {
pub fn new(operand: Expression, source_range: SourceRange) -> Self {
pub fn new(node_id: NodeId, operand: Expression, source_range: SourceRange) -> Self {
Self {
node_id,
operand: operand.into(),
source_range,
type_info: None,
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn source_range(&self) -> &SourceRange {
&self.source_range
}
@ -47,7 +54,10 @@ impl NegativeExpression {
self.operand.init_scopes(symbol_table, container_scope);
}
pub fn resolve_names_static(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names_static(
&self,
symbol_table: &SymbolTable,
) -> (NodesToSymbols, Diagnostics) {
self.operand.resolve_names_static(symbol_table)
}
@ -55,7 +65,7 @@ impl NegativeExpression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
self.operand
.resolve_names_field_init(symbol_table, self_class_symbol)
}
@ -64,11 +74,21 @@ impl NegativeExpression {
&self,
symbol_table: &SymbolTable,
self_class_symbol: &ClassSymbol,
) -> (NamesTable, Diagnostics) {
) -> (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,
@ -78,6 +98,7 @@ impl NegativeExpression {
.check_field_initializer_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_constructor_local_names(
&self,
symbol_table: &SymbolTable,
@ -87,6 +108,7 @@ impl NegativeExpression {
.check_constructor_local_names(symbol_table, class_symbol)
}
#[deprecated]
pub fn check_method_local_names(
&self,
symbol_table: &SymbolTable,
@ -96,10 +118,35 @@ impl NegativeExpression {
.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)
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,

View File

@ -1,13 +1,15 @@
use crate::ast::NamesTable;
use crate::ast::type_use::TypeUse;
use crate::ast::{NodeId, NodesToSymbols};
use crate::diagnostic::{Diagnostic, Diagnostics};
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;
pub struct Parameter {
node_id: NodeId,
declared_name: Rc<str>,
declared_name_source_range: SourceRange,
type_use: TypeUse,
@ -16,11 +18,13 @@ pub struct Parameter {
impl Parameter {
pub fn new(
node_id: NodeId,
declared_name: &str,
declared_name_source_range: SourceRange,
type_use: TypeUse,
) -> Self {
Self {
node_id,
declared_name: declared_name.into(),
declared_name_source_range,
type_use,
@ -28,6 +32,10 @@ impl Parameter {
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn declared_name(&self) -> &str {
&self.declared_name
}
@ -49,14 +57,16 @@ impl Parameter {
)
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
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
@ -67,6 +77,10 @@ impl Parameter {
.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,

View File

@ -1,8 +1,8 @@
use crate::ast::NamesTable;
use crate::ast::assign_statement::AssignStatement;
use crate::ast::expression_statement::ExpressionStatement;
use crate::ast::ir_builder::IrBuilder;
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;
@ -35,7 +35,7 @@ impl Statement {
pub fn resolve_names_static(
&self,
symbol_table: &mut SymbolTable,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
match self {
Statement::Let(let_statement) => let_statement.resolve_names_static(symbol_table),
Statement::Expression(expression_statement) => {
@ -52,7 +52,7 @@ impl Statement {
symbol_table: &mut SymbolTable,
self_class_symbol: &ClassSymbol,
initialized_fields: &mut HashSet<Rc<str>>,
) -> (NamesTable, Diagnostics) {
) -> (NodesToSymbols, Diagnostics) {
match self {
Statement::Let(let_statement) => {
let_statement.resolve_names_ctor(symbol_table, self_class_symbol)
@ -68,6 +68,25 @@ impl Statement {
}
}
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,
@ -86,6 +105,7 @@ impl Statement {
}
}
#[deprecated]
pub fn analyze_method_local_names(
&self,
symbol_table: &mut SymbolTable,
@ -104,6 +124,7 @@ impl Statement {
}
}
#[deprecated]
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
match self {
Statement::Let(let_statement) => {
@ -118,6 +139,27 @@ impl Statement {
}
}
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)
}
}
}
pub fn type_check(
&mut self,
symbol_table: &SymbolTable,

View File

@ -1,22 +1,29 @@
use crate::ast::NodeId;
use crate::source_range::SourceRange;
use crate::type_info::TypeInfo;
pub struct StringLiteral {
node_id: NodeId,
content: String,
source_range: SourceRange,
type_info: &'static TypeInfo,
}
impl StringLiteral {
pub fn new(content: &str, source_range: SourceRange) -> Self {
pub fn new(node_id: NodeId, content: &str, source_range: SourceRange) -> Self {
const TYPE_INFO: TypeInfo = TypeInfo::String;
Self {
node_id,
content: content.into(),
source_range,
type_info: &TYPE_INFO,
}
}
pub fn node_id(&self) -> NodeId {
self.node_id
}
pub fn content(&self) -> &str {
&self.content
}

View File

@ -1,6 +1,6 @@
use crate::ast::{NamesTable, NodeId};
use crate::ast::{NodeId, NodesToSymbols};
use crate::diagnostic::{Diagnostic, Diagnostics};
use crate::diagnostic_factories::symbol_not_found;
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::symbol::type_symbol::TypeSymbol;
@ -46,7 +46,7 @@ impl TypeUse {
}
}
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NamesTable, Diagnostics) {
pub fn resolve_names(&self, symbol_table: &SymbolTable) -> (NodesToSymbols, Diagnostics) {
let mut diagnostics = Vec::new();
let mut resolved_names = HashMap::new();
@ -75,6 +75,7 @@ impl TypeUse {
(resolved_names, diagnostics)
}
#[deprecated]
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
@ -96,6 +97,7 @@ impl TypeUse {
diagnostics
}
#[deprecated]
pub fn gather_types(
&self,
symbol_table: &SymbolTable,
@ -111,6 +113,36 @@ impl TypeUse {
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,

View File

@ -39,18 +39,39 @@ pub fn compile_compilation_units(inputs: &HashMap<FileId, &str>) -> Result<(), D
// gather unordered symbols
let all_symbols = compilation_units
.values()
.flat_map(|compilation_unit| compilation_unit.gather_unordered_symbols())
.flat_map(|compilation_unit| compilation_unit.declared_symbols())
.collect::<Vec<_>>();
try_insert_symbols_into(all_symbols, &mut symbol_table)?;
// now we can just finish each compilation unit, since we have the symbols
let mut diagnostics = Vec::new();
for compilation_unit in compilation_units.values() {
let (resolved_names, mut ds) = compilation_unit.resolve_names(&mut symbol_table);
let (nodes_to_symbols, mut ds) = compilation_unit.resolve_names(&mut 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, resolved_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);
}
}
Ok(())

View File

@ -1,11 +1,15 @@
use crate::diagnostic::{Diagnostic, SecondaryLabel};
use crate::error_codes::{
ASSIGN_LHS_IMMUTABLE, CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT, NOT_ASSIGNABLE,
OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT,
ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE,
CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE, CLASS_NO_CONSTRUCTOR, FIELD_NO_TYPE_OR_INIT,
MISMATCHED_TYPES, NOT_ASSIGNABLE, OUTER_CLASS_FIELD_USED_IN_INIT,
OUTER_CLASS_METHOD_USED_IN_INIT, RECEIVER_NOT_CALLABLE, SELF_CONSTRUCTOR_USED_IN_INIT,
SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND,
UNARY_INCOMPATIBLE_TYPE, WRONG_NUMBER_OF_ARGUMENTS,
};
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use crate::type_info::TypeInfo;
pub fn symbol_not_found(name: &str, source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
@ -135,3 +139,135 @@ pub fn cannot_reassign_immutable_field(source_range: &SourceRange) -> Diagnostic
)
.with_error_code(ASSIGN_LHS_IMMUTABLE)
}
pub fn cannot_provide_generic_args_generic_type(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Cannot provide generic arguments to an already generic type.",
source_range.start(),
source_range.end(),
)
.with_error_code(CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE)
}
pub fn must_be_l_value(source_range: &SourceRange) -> Diagnostic {
Diagnostic::new(
"Left-hand side of assign mut be an L value",
source_range.start(),
source_range.end(),
)
.with_error_code(ASSIGN_NO_L_VALUE)
}
pub fn destination_must_be_mutable(
source_range: &SourceRange,
secondary_source_range: Option<&SourceRange>,
) -> Diagnostic {
let secondary_label = secondary_source_range.map(|sr| {
SecondaryLabel::new(
sr.start(),
sr.end(),
Some("Destination declared here is immutable".to_string()),
)
});
let mut diagnostic = Diagnostic::new(
"Destination is immutable and cannot be reassigned.",
source_range.start(),
source_range.end(),
)
.with_error_code(ASSIGN_LHS_IMMUTABLE);
if let Some(secondary_label) = secondary_label {
diagnostic = diagnostic.with_secondary_labels(&[secondary_label])
}
diagnostic
}
pub fn mismatched_assign_types(
rhs_type: &TypeInfo,
lhs_type: &TypeInfo,
source_range: &SourceRange,
secondary_source_range: Option<&SourceRange>,
) -> Diagnostic {
let secondary_label = secondary_source_range.map(|sr| {
SecondaryLabel::new(
sr.start(),
sr.end(),
Some(format!(
"Destination declared here is of type {}.",
lhs_type
)),
)
});
let mut diagnostic = Diagnostic::new(
&format!("Mismatched types: right-hand side of type {} is not assignable to left-hand side of type {}", rhs_type, lhs_type),
source_range.start(),
source_range.end(),
)
.with_error_code(ASSIGN_MISMATCHED_TYPES);
if let Some(secondary_label) = secondary_label {
diagnostic = diagnostic.with_secondary_labels(&[secondary_label])
}
diagnostic
}
pub fn receiver_not_callable(
receiver_type_info: &TypeInfo,
source_range: &SourceRange,
) -> Diagnostic {
Diagnostic::new(
&format!("Receiver of type {} is not callable.", receiver_type_info),
source_range.start(),
source_range.end(),
)
.with_error_code(RECEIVER_NOT_CALLABLE)
}
pub fn wrong_number_of_arguments(
source_range: &SourceRange,
found: usize,
expected: usize,
) -> Diagnostic {
Diagnostic::new(
&format!(
"Wrong number of arguments: expected {} but found {}",
expected, found
),
source_range.start(),
source_range.end(),
)
.with_error_code(WRONG_NUMBER_OF_ARGUMENTS)
}
pub fn mismatched_types(
expected_type_info: &TypeInfo,
found_type_info: &TypeInfo,
source_range: &SourceRange,
) -> Diagnostic {
Diagnostic::new(
&format!(
"Mismatched types; expected {} but found {}",
expected_type_info, found_type_info
),
source_range.start(),
source_range.end(),
)
.with_error_code(MISMATCHED_TYPES)
}
pub fn unary_incompatible_type(
source_range: &SourceRange,
operator_name: &str,
type_info: &TypeInfo,
) -> Diagnostic {
Diagnostic::new(
&format!("Cannot apply {} to {}", operator_name, type_info),
source_range.start(),
source_range.end(),
)
.with_error_code(UNARY_INCOMPATIBLE_TYPE)
}

View File

@ -20,3 +20,8 @@ pub const OUTER_CLASS_METHOD_USED_IN_INIT: ErrorCode = 27;
pub const FIELD_NO_TYPE_OR_INIT: ErrorCode = 28;
pub const CLASS_NO_CONSTRUCTOR: ErrorCode = 29;
pub const NOT_ASSIGNABLE: ErrorCode = 30;
pub const CANNOT_PROVIDE_GENERIC_ARGS_GENERIC_TYPE: ErrorCode = 31;
pub const RECEIVER_NOT_CALLABLE: ErrorCode = 32;
pub const WRONG_NUMBER_OF_ARGUMENTS: ErrorCode = 33;
pub const MISMATCHED_TYPES: ErrorCode = 34;
pub const UNARY_INCOMPATIBLE_TYPE: ErrorCode = 35;

View File

@ -589,6 +589,7 @@ impl<'a> Parser<'a> {
&& let Some(type_use) = maybe_type_use
{
let parameter = Parameter::new(
self.next_node_id(),
self.token_text(&identifier),
SourceRange::new(identifier.start(), identifier.end()),
type_use,
@ -952,6 +953,7 @@ impl<'a> Parser<'a> {
if let Some(identifier) = maybe_identifier {
let let_statement = LetStatement::new(
self.next_node_id(),
self.token_text(&identifier),
SourceRange::new(identifier.start(), identifier.end()),
is_mut,
@ -974,7 +976,7 @@ impl<'a> Parser<'a> {
(Statement::Assign(assign_statement), diagnostics)
} else {
(
Statement::Expression(ExpressionStatement::new(base)),
Statement::Expression(ExpressionStatement::new(self.next_node_id(), base)),
diagnostics,
)
}
@ -1008,6 +1010,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::BitwiseOr,
@ -1030,6 +1033,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::BitwiseXor,
@ -1053,6 +1057,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::BitwiseAnd,
@ -1084,6 +1089,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::LeftShift,
@ -1103,6 +1109,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::RightShift,
@ -1133,6 +1140,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::Add,
@ -1147,6 +1155,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::Subtract,
@ -1176,6 +1185,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::Multiply,
@ -1190,6 +1200,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::Divide,
@ -1204,6 +1215,7 @@ impl<'a> Parser<'a> {
let source_range =
SourceRange::new(base.source_range().start(), rhs.source_range().end());
base = Expression::Binary(BinaryExpression::new(
self.next_node_id(),
base,
rhs,
BinaryOperation::Modulo,
@ -1242,7 +1254,11 @@ impl<'a> Parser<'a> {
let source_range = SourceRange::new(operator_token.start(), base.source_range().end());
match operator_token.kind() {
TokenKind::Minus => {
base = Expression::Negative(NegativeExpression::new(base, source_range));
base = Expression::Negative(NegativeExpression::new(
self.next_node_id(),
base,
source_range,
));
}
_ => unreachable!(),
}
@ -1281,6 +1297,7 @@ impl<'a> Parser<'a> {
diagnostics.append(&mut self.advance());
(
Expression::Integer(IntegerLiteral::new(
self.next_node_id(),
i32::from_str(raw).unwrap(),
source_range,
)),
@ -1293,6 +1310,7 @@ impl<'a> Parser<'a> {
diagnostics.append(&mut self.advance());
(
Expression::Double(DoubleLiteral::new(
self.next_node_id(),
f64::from_str(raw).unwrap(),
source_range,
)),
@ -1305,6 +1323,7 @@ impl<'a> Parser<'a> {
diagnostics.append(&mut self.advance());
(
Expression::String(StringLiteral::new(
self.next_node_id(),
&with_quotes[1..with_quotes.len() - 1],
source_range,
)),
@ -1352,7 +1371,10 @@ impl<'a> Parser<'a> {
SourceRange::new(callee.source_range().start(), callee.source_range().end())
};
(Call::new(callee, arguments, source_range), diagnostics)
(
Call::new(self.next_node_id(), callee, arguments, source_range),
diagnostics,
)
}
fn expression_list(&mut self) -> ParseResult<Vec<Expression>> {

View File

@ -6,6 +6,7 @@ use std::rc::Rc;
pub enum CallableSymbol {
Function(Rc<FunctionSymbol>),
Constructor(Rc<ConstructorSymbol>),
ErrorPlaceholder,
}
impl CallableSymbol {
@ -15,6 +16,7 @@ impl CallableSymbol {
CallableSymbol::Constructor(constructor_symbol) => {
constructor_symbol.parameters().to_vec()
}
CallableSymbol::ErrorPlaceholder => Vec::new(),
}
}
}

View File

@ -1,10 +1,12 @@
use crate::source_range::SourceRange;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::constructor_symbol::ConstructorSymbol;
use crate::symbol::expressible_symbol::ExpressibleSymbol;
use crate::symbol::field_symbol::FieldSymbol;
use crate::symbol::function_symbol::FunctionSymbol;
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
use crate::symbol::parameter_symbol::ParameterSymbol;
use crate::symbol::type_symbol::TypeSymbol;
use crate::symbol::variable_symbol::VariableSymbol;
use std::rc::Rc;
@ -19,7 +21,7 @@ pub mod parameter_symbol;
pub mod type_symbol;
pub mod variable_symbol;
#[derive(Eq, PartialEq, Hash)]
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum Symbol {
Class(Rc<ClassSymbol>),
GenericParameter(Rc<GenericParameterSymbol>),
@ -76,4 +78,38 @@ impl Symbol {
Symbol::Variable(variable_symbol) => Some(variable_symbol.declared_name_source_range()),
}
}
pub fn unwrap_type_symbol(&self) -> TypeSymbol {
match self {
Symbol::Class(class_symbol) => TypeSymbol::Class(class_symbol.clone()),
Symbol::GenericParameter(generic_parameter_symbol) => {
TypeSymbol::GenericParameter(generic_parameter_symbol.clone())
}
_ => panic!(),
}
}
pub fn unwrap_expressible_symbol(&self) -> ExpressibleSymbol {
match self {
Symbol::Class(class_symbol) => ExpressibleSymbol::Class(class_symbol.clone()),
Symbol::Field(field_symbol) => ExpressibleSymbol::Field(field_symbol.clone()),
Symbol::Function(function_symbol) => {
ExpressibleSymbol::Function(function_symbol.clone())
}
Symbol::Parameter(parameter_symbol) => {
ExpressibleSymbol::Parameter(parameter_symbol.clone())
}
Symbol::Variable(variable_symbol) => {
ExpressibleSymbol::Variable(variable_symbol.clone())
}
_ => panic!(),
}
}
pub fn unwrap_function_symbol(&self) -> &Rc<FunctionSymbol> {
match self {
Symbol::Function(function_symbol) => function_symbol,
_ => panic!(),
}
}
}

View File

@ -1,4 +1,5 @@
use crate::source_range::SourceRange;
use crate::symbol::Symbol;
use std::hash::{Hash, Hasher};
use std::rc::Rc;

View File

@ -11,9 +11,15 @@ pub enum TypeInfo {
Double,
String,
Function(Rc<FunctionSymbol>),
#[deprecated]
Class(Rc<ClassSymbol>),
ParameterizedClass(Rc<ClassSymbol>, Vec<TypeInfo>),
GenericType(Rc<GenericParameterSymbol>),
Void,
PlaceholderError,
}
impl Display for TypeInfo {
@ -36,10 +42,23 @@ impl Display for TypeInfo {
TypeInfo::Class(class_symbol) => {
write!(f, "Class({:?})", class_symbol)
}
TypeInfo::ParameterizedClass(class_symbol, arguments) => {
write!(
f,
"ParameterizedClass({:?}<{}>)",
class_symbol,
arguments
.iter()
.map(|a| a.to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
TypeInfo::GenericType(generic_parameter_symbol) => {
write!(f, "{}", generic_parameter_symbol.declared_name())
}
TypeInfo::Void => write!(f, "Void"),
TypeInfo::PlaceholderError => write!(f, "<PlaceholderError>"),
}
}
}
@ -72,6 +91,16 @@ impl TypeInfo {
TypeInfo::Class(other_class_symbol) => class_symbol == other_class_symbol,
_ => false,
},
TypeInfo::ParameterizedClass(class_symbol, arguments) => match other {
TypeInfo::ParameterizedClass(other_class_symbol, other_arguments) => {
if arguments.is_empty() && other_arguments.is_empty() {
class_symbol == other_class_symbol
} else {
todo!()
}
}
_ => false,
},
TypeInfo::GenericType(generic_parameter_symbol) => {
// if generic_parameter_symbol.extends().len() > 0 {
// unimplemented!(
@ -83,6 +112,7 @@ impl TypeInfo {
TypeInfo::Void => {
matches!(other, TypeInfo::Void)
}
TypeInfo::PlaceholderError => false,
}
}