Major refactor of frontend ast semantic analysis. WIP.
This commit is contained in:
parent
8724c07ae2
commit
cf92356585
@ -2,7 +2,7 @@ mod repl;
|
|||||||
mod run;
|
mod run;
|
||||||
|
|
||||||
use crate::repl::repl;
|
use crate::repl::repl;
|
||||||
use crate::run::run;
|
use crate::run::compile_and_run_script;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ fn main() {
|
|||||||
show_ir,
|
show_ir,
|
||||||
register_count,
|
register_count,
|
||||||
} => {
|
} => {
|
||||||
run(script, *show_asm, *show_ir, *register_count);
|
compile_and_run_script(script, *show_asm, *show_ir, *register_count);
|
||||||
}
|
}
|
||||||
SubCommand::Repl { register_count } => {
|
SubCommand::Repl { register_count } => {
|
||||||
repl(*register_count);
|
repl(*register_count);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use dmc_lib::lexer::Lexer;
|
|||||||
use dmc_lib::parser::parse_expression;
|
use dmc_lib::parser::parse_expression;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dmc_lib::token::TokenKind;
|
use dmc_lib::token::TokenKind;
|
||||||
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::operand::Operand;
|
use dvm_lib::vm::operand::Operand;
|
||||||
@ -97,24 +98,30 @@ fn compile_expression(
|
|||||||
let mut expression = parse_result?;
|
let mut expression = parse_result?;
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let mut types_table = TypesTable::new();
|
||||||
|
|
||||||
// "fake" scopes
|
// "fake" scopes
|
||||||
symbol_table.push_module_scope("__repl_module");
|
symbol_table.push_module_scope("__repl_module");
|
||||||
symbol_table.push_function_scope("__repl_function");
|
let function_scope_id = symbol_table.push_function_scope("__repl_function");
|
||||||
|
|
||||||
expression.gather_declared_names(&mut symbol_table)?;
|
expression.init_scopes(&mut symbol_table, function_scope_id);
|
||||||
|
|
||||||
symbol_table.pop_scope(); // function
|
symbol_table.pop_scope(); // function
|
||||||
symbol_table.pop_scope(); // module
|
symbol_table.pop_scope(); // module
|
||||||
|
|
||||||
expression.check_name_usages(&symbol_table)?;
|
let diagnostics = expression.check_static_fn_local_names(&symbol_table);
|
||||||
expression.type_check(&symbol_table)?;
|
if !diagnostics.is_empty() {
|
||||||
|
return Err(diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.type_check(&symbol_table, &mut types_table)?;
|
||||||
|
|
||||||
// synthesize a function
|
// synthesize a function
|
||||||
let mut ir_builder = IrBuilder::new();
|
let mut ir_builder = IrBuilder::new();
|
||||||
let entry_block_id = ir_builder.new_block();
|
let entry_block_id = ir_builder.new_block();
|
||||||
|
|
||||||
let maybe_ir_expression = expression.to_ir_expression(&mut ir_builder, &symbol_table);
|
let maybe_ir_expression =
|
||||||
|
expression.to_ir_expression(&mut ir_builder, &symbol_table, &types_table);
|
||||||
|
|
||||||
// if Some, return the value
|
// if Some, return the value
|
||||||
ir_builder
|
ir_builder
|
||||||
@ -126,8 +133,8 @@ fn compile_expression(
|
|||||||
|
|
||||||
let mut ir_function = IrFunction::new(
|
let mut ir_function = IrFunction::new(
|
||||||
"__repl".into(),
|
"__repl".into(),
|
||||||
&[],
|
vec![],
|
||||||
expression.type_info(),
|
expression.type_info(&symbol_table, &types_table),
|
||||||
entry_block.clone(),
|
entry_block.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use dmc_lib::constants_table::ConstantsTable;
|
|||||||
use dmc_lib::diagnostic::Diagnostic;
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::operand::Operand;
|
use dvm_lib::vm::operand::Operand;
|
||||||
@ -14,45 +15,42 @@ use dvm_lib::vm::{CallStack, DvmContext, call};
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usize) {
|
pub fn compile_and_run_script(
|
||||||
|
script: &PathBuf,
|
||||||
|
show_ir: bool,
|
||||||
|
show_asm: bool,
|
||||||
|
register_count: usize,
|
||||||
|
) {
|
||||||
let input = std::fs::read_to_string(script).unwrap();
|
let input = std::fs::read_to_string(script).unwrap();
|
||||||
|
|
||||||
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
|
let mut files: SimpleFiles<&str, &str> = SimpleFiles::new();
|
||||||
let script_file_id = files.add(script.to_str().unwrap(), &input);
|
let script_file_id = files.add(script.to_str().unwrap(), &input);
|
||||||
|
|
||||||
let parse_result = parse_compilation_unit(&input);
|
match run(&input, show_ir, show_asm, register_count) {
|
||||||
let mut compilation_unit = match parse_result {
|
Ok(_) => {}
|
||||||
Ok(compilation_unit) => compilation_unit,
|
|
||||||
Err(diagnostics) => {
|
Err(diagnostics) => {
|
||||||
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
|
check_and_report_diagnostics(&files, script_file_id, &diagnostics);
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
input: &str,
|
||||||
|
show_ir: bool,
|
||||||
|
show_asm: bool,
|
||||||
|
register_count: usize,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut compilation_unit = parse_compilation_unit(&input)?;
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let mut types_table = TypesTable::new();
|
||||||
|
|
||||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
compilation_unit.init_scopes(&mut symbol_table);
|
||||||
Ok(_) => {}
|
compilation_unit.gather_symbols_into(&mut symbol_table)?;
|
||||||
Err(diagnostics) => {
|
compilation_unit.check_names(&mut symbol_table)?;
|
||||||
report_and_exit(&diagnostics, script_file_id, &files);
|
compilation_unit.type_check(&symbol_table, &mut types_table)?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.check_name_usages(&symbol_table) {
|
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table);
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
report_and_exit(&diagnostics, script_file_id, &files);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
report_and_exit(&diagnostics, script_file_id, &files);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table);
|
|
||||||
|
|
||||||
if show_ir {
|
if show_ir {
|
||||||
for ir_function in &ir_functions {
|
for ir_function in &ir_functions {
|
||||||
@ -117,6 +115,8 @@ pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usiz
|
|||||||
if let Some(value) = result {
|
if let Some(value) = result {
|
||||||
println!("{}", value);
|
println!("{}", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_and_report_diagnostics(
|
fn check_and_report_diagnostics(
|
||||||
|
|||||||
@ -6,8 +6,10 @@ use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_N
|
|||||||
use crate::ir::ir_assign::IrAssign;
|
use crate::ir::ir_assign::IrAssign;
|
||||||
use crate::ir::ir_set_field::IrSetField;
|
use crate::ir::ir_set_field::IrSetField;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
pub struct AssignStatement {
|
pub struct AssignStatement {
|
||||||
destination: Box<Expression>,
|
destination: Box<Expression>,
|
||||||
@ -26,68 +28,68 @@ impl AssignStatement {
|
|||||||
&self.destination
|
&self.destination
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
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 check_constructor_local_names(
|
||||||
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_symbol: &ClassSymbol,
|
||||||
|
) -> Vec<Diagnostic> {
|
||||||
|
[
|
||||||
|
self.destination
|
||||||
|
.check_constructor_local_names(symbol_table, class_symbol),
|
||||||
|
self.value
|
||||||
|
.check_constructor_local_names(symbol_table, class_symbol),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
match self.value.gather_declared_names(symbol_table) {
|
match self.value.type_check(symbol_table, types_table) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(mut value_diagnostics) => {
|
Err(mut value_diagnostics) => {
|
||||||
diagnostics.append(&mut value_diagnostics);
|
diagnostics.append(&mut value_diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.destination.gather_declared_names(symbol_table) {
|
match self.destination.type_check(symbol_table, types_table) {
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut destination_diagnostics) => {
|
|
||||||
diagnostics.append(&mut destination_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
match self.value.check_name_usages(symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut value_diagnostics) => {
|
|
||||||
diagnostics.append(&mut value_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.destination.check_name_usages(symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut destination_diagnostics) => {
|
|
||||||
diagnostics.append(&mut destination_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
match self.value.type_check(symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut value_diagnostics) => {
|
|
||||||
diagnostics.append(&mut value_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.destination.type_check(symbol_table) {
|
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(mut destination_diagnostics) => {
|
Err(mut destination_diagnostics) => {
|
||||||
diagnostics.append(&mut destination_diagnostics);
|
diagnostics.append(&mut destination_diagnostics);
|
||||||
@ -97,10 +99,18 @@ impl AssignStatement {
|
|||||||
// check destination is l value
|
// check destination is l value
|
||||||
match &*self.destination {
|
match &*self.destination {
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
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
|
// check mutable
|
||||||
if !expressible_symbol.is_mut() {
|
if !is_mut {
|
||||||
let secondary_label = SecondaryLabel::new(
|
let secondary_label = SecondaryLabel::new(
|
||||||
expressible_symbol.source_range().start(),
|
expressible_symbol.source_range().start(),
|
||||||
expressible_symbol.source_range().end(),
|
expressible_symbol.source_range().end(),
|
||||||
@ -119,8 +129,17 @@ impl AssignStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check assignable
|
// check assignable
|
||||||
let lhs_type = expressible_symbol.type_info();
|
let lhs_type = match &expressible_symbol {
|
||||||
let rhs_type = self.value.type_info();
|
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) {
|
if !lhs_type.is_assignable_from(rhs_type) {
|
||||||
let secondary_label = SecondaryLabel::new(
|
let secondary_label = SecondaryLabel::new(
|
||||||
expressible_symbol.source_range().start(),
|
expressible_symbol.source_range().start(),
|
||||||
@ -168,29 +187,37 @@ impl AssignStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) {
|
||||||
let destination_symbol = match &*self.destination {
|
let destination_symbol = match &*self.destination {
|
||||||
Expression::Identifier(identifier) => identifier.expressible_symbol(),
|
Expression::Identifier(identifier) => symbol_table
|
||||||
|
.find_expressible_symbol(identifier.scope_id(), identifier.name())
|
||||||
|
.unwrap(),
|
||||||
_ => unreachable!("Destination must be a mutable L value"),
|
_ => unreachable!("Destination must be a mutable L value"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ir_statement = match destination_symbol {
|
let ir_statement = match destination_symbol {
|
||||||
ExpressibleSymbol::Field(field_symbol) => {
|
ExpressibleSymbol::Field(field_symbol) => {
|
||||||
let mut_field_pointer_variable =
|
let mut_field_pointer_variable =
|
||||||
get_or_init_mut_field_pointer_variable(builder, field_symbol).clone();
|
get_or_init_mut_field_pointer_variable(builder, &field_symbol).clone();
|
||||||
let ir_set_field = IrSetField::new(
|
let ir_set_field = IrSetField::new(
|
||||||
&mut_field_pointer_variable,
|
&mut_field_pointer_variable,
|
||||||
self.value
|
self.value
|
||||||
.to_ir_expression(builder, symbol_table)
|
.to_ir_expression(builder, symbol_table, types_table)
|
||||||
.expect("Attempt to convert non-value to value"),
|
.expect("Attempt to convert non-value to value"),
|
||||||
);
|
);
|
||||||
IrStatement::SetField(ir_set_field)
|
IrStatement::SetField(ir_set_field)
|
||||||
}
|
}
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||||
let vr_variable = variable_symbol.borrow().vr_variable().clone();
|
let vr_variable = builder.local_variables().get(&variable_symbol).unwrap();
|
||||||
let ir_assign = IrAssign::new(
|
let ir_assign = IrAssign::new(
|
||||||
vr_variable,
|
vr_variable.clone(),
|
||||||
self.value.to_ir_operation(builder, symbol_table),
|
self.value
|
||||||
|
.to_ir_operation(builder, symbol_table, types_table),
|
||||||
);
|
);
|
||||||
IrStatement::Assign(ir_assign)
|
IrStatement::Assign(ir_assign)
|
||||||
}
|
}
|
||||||
@ -203,12 +230,24 @@ impl AssignStatement {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
|
fn compile_up_to_type_check(
|
||||||
|
compilation_unit: &mut CompilationUnit,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
compilation_unit.init_scopes(symbol_table);
|
||||||
|
compilation_unit.gather_symbols_into(symbol_table)?;
|
||||||
|
compilation_unit.check_names(symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn finds_mismatched_types() {
|
fn finds_mismatched_types() -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut compilation_unit = parse_compilation_unit(
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
"
|
"
|
||||||
fn main()
|
fn main()
|
||||||
@ -219,52 +258,41 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
compilation_unit
|
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?;
|
||||||
.gather_declared_names(&mut symbol_table)
|
let mut types_table = TypesTable::new();
|
||||||
.unwrap();
|
let diagnostics = compilation_unit
|
||||||
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
.type_check(&symbol_table, &mut types_table)
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
.unwrap_err();
|
||||||
Ok(_) => {
|
assert_eq!(diagnostics.len(), 1);
|
||||||
panic!("Type check missed diagnostic.");
|
assert_eq!(
|
||||||
}
|
diagnostics[0].error_code().unwrap(),
|
||||||
Err(diagnostics) => {
|
ASSIGN_MISMATCHED_TYPES
|
||||||
assert_eq!(diagnostics.len(), 1);
|
);
|
||||||
assert_eq!(
|
Ok(())
|
||||||
diagnostics[0].error_code().unwrap(),
|
|
||||||
ASSIGN_MISMATCHED_TYPES
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn finds_no_l_value() {
|
fn finds_no_l_value() -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut compilation_unit = parse_compilation_unit(
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
"
|
"
|
||||||
fn main()
|
fn main()
|
||||||
42 = 42
|
42 = 42
|
||||||
end
|
end
|
||||||
",
|
",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
compilation_unit
|
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?;
|
||||||
.gather_declared_names(&mut symbol_table)
|
let mut types_table = TypesTable::new();
|
||||||
.unwrap();
|
let diagnostics = compilation_unit
|
||||||
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
.type_check(&symbol_table, &mut types_table)
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
.unwrap_err();
|
||||||
Ok(_) => {
|
assert_eq!(diagnostics.len(), 1);
|
||||||
panic!("Type check missed diagnostic.");
|
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_NO_L_VALUE);
|
||||||
}
|
Ok(())
|
||||||
Err(diagnostics) => {
|
|
||||||
assert_eq!(diagnostics.len(), 1);
|
|
||||||
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_NO_L_VALUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn finds_immutable_destination() {
|
fn finds_immutable_destination() -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut compilation_unit = parse_compilation_unit(
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
"
|
"
|
||||||
fn main()
|
fn main()
|
||||||
@ -272,21 +300,15 @@ mod tests {
|
|||||||
x = 43
|
x = 43
|
||||||
end
|
end
|
||||||
",
|
",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
compilation_unit
|
compile_up_to_type_check(&mut compilation_unit, &mut symbol_table)?;
|
||||||
.gather_declared_names(&mut symbol_table)
|
let mut types_table = TypesTable::new();
|
||||||
.unwrap();
|
let diagnostics = compilation_unit
|
||||||
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
.type_check(&symbol_table, &mut types_table)
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
.unwrap_err();
|
||||||
Ok(_) => {
|
assert_eq!(diagnostics.len(), 1);
|
||||||
panic!("Type check missed diagnostic.");
|
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_LHS_IMMUTABLE);
|
||||||
}
|
Ok(())
|
||||||
Err(diagnostics) => {
|
|
||||||
assert_eq!(diagnostics.len(), 1);
|
|
||||||
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_LHS_IMMUTABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,10 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
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::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use crate::{diagnostics_result, handle_diagnostic, handle_diagnostics, maybe_return_diagnostics};
|
use crate::{diagnostics_result, handle_diagnostic, handle_diagnostics, maybe_return_diagnostics};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -72,45 +74,79 @@ impl BinaryExpression {
|
|||||||
self.type_info.as_ref().unwrap()
|
self.type_info.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.lhs.init_scopes(symbol_table, container_scope);
|
||||||
symbol_table: &mut SymbolTable,
|
self.rhs.init_scopes(symbol_table, container_scope);
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let diagnostics = [&mut self.lhs, &mut self.rhs]
|
|
||||||
.iter_mut()
|
|
||||||
.map(|expression| expression.gather_declared_names(symbol_table))
|
|
||||||
.filter_map(|result| result.err())
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<Diagnostic>>();
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_field_initializer_names(
|
||||||
let diagnostics: Vec<Diagnostic> = [&mut self.lhs, &mut self.rhs]
|
&self,
|
||||||
.iter_mut()
|
symbol_table: &SymbolTable,
|
||||||
.map(|expression| expression.check_name_usages(symbol_table))
|
class_symbol: &ClassSymbol,
|
||||||
.filter_map(Result::err)
|
) -> Vec<Diagnostic> {
|
||||||
.flatten()
|
[
|
||||||
.collect();
|
self.lhs
|
||||||
if diagnostics.is_empty() {
|
.check_field_initializer_names(symbol_table, class_symbol),
|
||||||
Ok(())
|
self.rhs
|
||||||
} else {
|
.check_field_initializer_names(symbol_table, class_symbol),
|
||||||
Err(diagnostics)
|
]
|
||||||
}
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 check_op(
|
fn check_op(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
check: impl Fn(&TypeInfo, &TypeInfo) -> bool,
|
check: impl Fn(&TypeInfo, &TypeInfo) -> bool,
|
||||||
op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo,
|
op_result: impl Fn(&TypeInfo, &TypeInfo) -> TypeInfo,
|
||||||
lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String,
|
lazy_diagnostic_message: impl Fn(&TypeInfo, &TypeInfo) -> String,
|
||||||
) -> Result<(), Diagnostic> {
|
) -> Result<(), Diagnostic> {
|
||||||
let lhs_type_info = self.lhs.type_info();
|
let lhs_type_info = self.lhs.type_info(symbol_table, types_table);
|
||||||
let rhs_type_info = self.rhs.type_info();
|
let rhs_type_info = self.rhs.type_info(symbol_table, types_table);
|
||||||
|
|
||||||
if check(lhs_type_info, rhs_type_info) {
|
if check(lhs_type_info, rhs_type_info) {
|
||||||
self.type_info = Some(op_result(lhs_type_info, rhs_type_info));
|
self.type_info = Some(op_result(lhs_type_info, rhs_type_info));
|
||||||
@ -128,11 +164,15 @@ impl BinaryExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
handle_diagnostics!(self.lhs.type_check(symbol_table), diagnostics);
|
handle_diagnostics!(self.lhs.type_check(symbol_table, types_table), diagnostics);
|
||||||
handle_diagnostics!(self.rhs.type_check(symbol_table), diagnostics);
|
handle_diagnostics!(self.rhs.type_check(symbol_table, types_table), diagnostics);
|
||||||
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
maybe_return_diagnostics!(diagnostics);
|
||||||
|
|
||||||
@ -140,6 +180,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::Multiply => {
|
BinaryOperation::Multiply => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_multiply(rhs),
|
|lhs, rhs| lhs.can_multiply(rhs),
|
||||||
|lhs, rhs| lhs.multiply_result(rhs),
|
|lhs, rhs| lhs.multiply_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -153,6 +195,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::Divide => {
|
BinaryOperation::Divide => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_divide(rhs),
|
|lhs, rhs| lhs.can_divide(rhs),
|
||||||
|lhs, rhs| lhs.divide_result(rhs),
|
|lhs, rhs| lhs.divide_result(rhs),
|
||||||
|lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs)
|
|lhs, rhs| format!("Incompatible types: cannot divide {} by {}", lhs, rhs)
|
||||||
@ -163,6 +207,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::Modulo => {
|
BinaryOperation::Modulo => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_modulo(rhs),
|
|lhs, rhs| lhs.can_modulo(rhs),
|
||||||
|lhs, rhs| lhs.modulo_result(rhs),
|
|lhs, rhs| lhs.modulo_result(rhs),
|
||||||
|lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs)
|
|lhs, rhs| format!("Incompatible types: cannot modulo {} by {}", lhs, rhs)
|
||||||
@ -173,6 +219,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::Add => {
|
BinaryOperation::Add => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_add(rhs),
|
|lhs, rhs| lhs.can_add(rhs),
|
||||||
|lhs, rhs| lhs.add_result(&rhs),
|
|lhs, rhs| lhs.add_result(&rhs),
|
||||||
|lhs, rhs| format!("Incompatible types: cannot add {} to {}.", rhs, lhs)
|
|lhs, rhs| format!("Incompatible types: cannot add {} to {}.", rhs, lhs)
|
||||||
@ -183,6 +231,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::Subtract => {
|
BinaryOperation::Subtract => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_subtract(rhs),
|
|lhs, rhs| lhs.can_subtract(rhs),
|
||||||
|lhs, rhs| lhs.subtract_result(rhs),
|
|lhs, rhs| lhs.subtract_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -196,6 +246,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::LeftShift => {
|
BinaryOperation::LeftShift => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_left_shift(rhs),
|
|lhs, rhs| lhs.can_left_shift(rhs),
|
||||||
|lhs, rhs| lhs.left_shift_result(rhs),
|
|lhs, rhs| lhs.left_shift_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -209,6 +261,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::RightShift => {
|
BinaryOperation::RightShift => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_right_shift(rhs),
|
|lhs, rhs| lhs.can_right_shift(rhs),
|
||||||
|lhs, rhs| lhs.right_shift_result(rhs),
|
|lhs, rhs| lhs.right_shift_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -222,6 +276,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::BitwiseAnd => {
|
BinaryOperation::BitwiseAnd => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_bitwise_and(rhs),
|
|lhs, rhs| lhs.can_bitwise_and(rhs),
|
||||||
|lhs, rhs| lhs.bitwise_and_result(rhs),
|
|lhs, rhs| lhs.bitwise_and_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -234,6 +290,8 @@ impl BinaryExpression {
|
|||||||
}
|
}
|
||||||
BinaryOperation::BitwiseXor => handle_diagnostic!(
|
BinaryOperation::BitwiseXor => handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_bitwise_xor(rhs),
|
|lhs, rhs| lhs.can_bitwise_xor(rhs),
|
||||||
|lhs, rhs| lhs.bitwise_xor_result(rhs),
|
|lhs, rhs| lhs.bitwise_xor_result(rhs),
|
||||||
|lhs, rhs| format!("Incompatible types: cannot bitwise xor {} by {}", lhs, rhs)
|
|lhs, rhs| format!("Incompatible types: cannot bitwise xor {} by {}", lhs, rhs)
|
||||||
@ -243,6 +301,8 @@ impl BinaryExpression {
|
|||||||
BinaryOperation::BitwiseOr => {
|
BinaryOperation::BitwiseOr => {
|
||||||
handle_diagnostic!(
|
handle_diagnostic!(
|
||||||
self.check_op(
|
self.check_op(
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|lhs, rhs| lhs.can_bitwise_or(rhs),
|
|lhs, rhs| lhs.can_bitwise_or(rhs),
|
||||||
|lhs, rhs| lhs.bitwise_or_result(rhs),
|
|lhs, rhs| lhs.bitwise_or_result(rhs),
|
||||||
|lhs, rhs| format!(
|
|lhs, rhs| format!(
|
||||||
@ -262,14 +322,15 @@ impl BinaryExpression {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> IrOperation {
|
) -> IrOperation {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.lhs
|
.lhs
|
||||||
.to_ir_expression(builder, symbol_table)
|
.to_ir_expression(builder, symbol_table, types_table)
|
||||||
.expect("Attempt to use a non-value expression in binary expression.");
|
.expect("Attempt to use a non-value expression in binary expression.");
|
||||||
let rhs = self
|
let rhs = self
|
||||||
.rhs
|
.rhs
|
||||||
.to_ir_expression(builder, symbol_table)
|
.to_ir_expression(builder, symbol_table, types_table)
|
||||||
.expect("Attempt to use a non-value expression in binary expression.");
|
.expect("Attempt to use a non-value expression in binary expression.");
|
||||||
let ir_binary_operation = match self.op {
|
let ir_binary_operation = match self.op {
|
||||||
BinaryOperation::Multiply => {
|
BinaryOperation::Multiply => {
|
||||||
@ -304,8 +365,9 @@ impl BinaryExpression {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> IrExpression {
|
) -> IrExpression {
|
||||||
let ir_operation = self.to_ir_operation(builder, symbol_table);
|
let ir_operation = self.to_ir_operation(builder, symbol_table, types_table);
|
||||||
let t_var = IrVariable::new_vr(
|
let t_var = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
|
|||||||
@ -6,15 +6,16 @@ use crate::ir::ir_call::IrCall;
|
|||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::callable_symbol::CallableSymbol;
|
use crate::symbol::callable_symbol::CallableSymbol;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
callee: Box<Expression>,
|
callee: Box<Expression>,
|
||||||
arguments: Vec<Expression>,
|
arguments: Vec<Expression>,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
return_type_info: Option<TypeInfo>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Call {
|
impl Call {
|
||||||
@ -23,7 +24,6 @@ impl Call {
|
|||||||
callee: callee.into(),
|
callee: callee.into(),
|
||||||
arguments,
|
arguments,
|
||||||
source_range,
|
source_range,
|
||||||
return_type_info: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,57 +35,92 @@ impl Call {
|
|||||||
self.arguments.iter().collect()
|
self.arguments.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut to_gather = vec![];
|
self.callee.as_mut().type_check(symbol_table, types_table)?;
|
||||||
to_gather.push(self.callee.as_mut());
|
|
||||||
to_gather.extend(&mut self.arguments);
|
|
||||||
|
|
||||||
let diagnostics: Vec<Diagnostic> = to_gather
|
|
||||||
.iter_mut()
|
|
||||||
.map(|expression| expression.gather_declared_names(symbol_table))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut to_check = vec![];
|
|
||||||
to_check.push(self.callee.as_mut());
|
|
||||||
to_check.extend(&mut self.arguments);
|
|
||||||
let diagnostics: Vec<Diagnostic> = to_check
|
|
||||||
.iter_mut()
|
|
||||||
.map(|expression| expression.check_name_usages(symbol_table))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
self.callee.as_mut().type_check(symbol_table)?;
|
|
||||||
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = self
|
let mut diagnostics: Vec<Diagnostic> = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|argument| argument.type_check(symbol_table))
|
.map(|argument| argument.type_check(symbol_table, types_table))
|
||||||
.filter_map(Result::err)
|
.filter_map(Result::err)
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// check that callee is callable
|
// check that callee is callable
|
||||||
let callable_symbol = match self.callee.type_info() {
|
let callable_symbol = match self.callee.type_info(symbol_table, types_table) {
|
||||||
TypeInfo::Function(function_symbol) => {
|
TypeInfo::Function(function_symbol) => {
|
||||||
CallableSymbol::Function(function_symbol.clone())
|
CallableSymbol::Function(function_symbol.clone())
|
||||||
}
|
}
|
||||||
@ -94,7 +129,7 @@ impl Call {
|
|||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
&format!(
|
&format!(
|
||||||
"Receiver of type {} is not callable.",
|
"Receiver of type {} is not callable.",
|
||||||
self.callee.type_info()
|
self.callee.type_info(symbol_table, types_table)
|
||||||
),
|
),
|
||||||
self.callee.source_range().start(),
|
self.callee.source_range().start(),
|
||||||
self.callee.source_range().end(),
|
self.callee.source_range().end(),
|
||||||
@ -103,9 +138,6 @@ impl Call {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// set return type
|
|
||||||
self.return_type_info = Some(callable_symbol.return_type_info());
|
|
||||||
|
|
||||||
// check arguments length
|
// check arguments length
|
||||||
let parameters = callable_symbol.parameters();
|
let parameters = callable_symbol.parameters();
|
||||||
if parameters.len() != self.arguments.len() {
|
if parameters.len() != self.arguments.len() {
|
||||||
@ -126,10 +158,10 @@ impl Call {
|
|||||||
|
|
||||||
// check argument types
|
// check argument types
|
||||||
for i in 0..parameters.len() {
|
for i in 0..parameters.len() {
|
||||||
let parameter = ¶meters[i].borrow();
|
let parameter = ¶meters[i];
|
||||||
let argument = &self.arguments[i];
|
let argument = &self.arguments[i];
|
||||||
let parameter_type_info = parameter.type_info();
|
let parameter_type_info = types_table.parameter_types().get(parameter).unwrap();
|
||||||
let argument_type_info = argument.type_info();
|
let argument_type_info = argument.type_info(symbol_table, types_table);
|
||||||
if !parameter_type_info.is_assignable_from(argument_type_info) {
|
if !parameter_type_info.is_assignable_from(argument_type_info) {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
&format!(
|
&format!(
|
||||||
@ -149,14 +181,30 @@ impl Call {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type_info(&self) -> &TypeInfo {
|
pub fn return_type_info<'a>(
|
||||||
self.return_type_info.as_ref().unwrap()
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &'a TypesTable,
|
||||||
|
) -> &'a TypeInfo {
|
||||||
|
let callable_symbol = self.get_callee_symbol(symbol_table);
|
||||||
|
match callable_symbol {
|
||||||
|
CallableSymbol::Function(function_symbol) => types_table
|
||||||
|
.function_return_types()
|
||||||
|
.get(&function_symbol)
|
||||||
|
.unwrap(),
|
||||||
|
CallableSymbol::Class(class_symbol) => types_table
|
||||||
|
.class_instance_types()
|
||||||
|
.get(&class_symbol)
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_callee_symbol(&self) -> CallableSymbol {
|
fn get_callee_symbol(&self, symbol_table: &SymbolTable) -> CallableSymbol {
|
||||||
match self.callee() {
|
match self.callee() {
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
let expressible_symbol = symbol_table
|
||||||
|
.find_expressible_symbol(identifier.scope_id(), identifier.name())
|
||||||
|
.unwrap();
|
||||||
match expressible_symbol {
|
match expressible_symbol {
|
||||||
ExpressibleSymbol::Function(function_symbol) => {
|
ExpressibleSymbol::Function(function_symbol) => {
|
||||||
CallableSymbol::Function(function_symbol.clone())
|
CallableSymbol::Function(function_symbol.clone())
|
||||||
@ -171,11 +219,16 @@ impl Call {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrCall {
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) -> IrCall {
|
||||||
let arguments: Vec<IrExpression> = self
|
let arguments: Vec<IrExpression> = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|argument| argument.to_ir_expression(builder, symbol_table))
|
.map(|argument| argument.to_ir_expression(builder, symbol_table, types_table))
|
||||||
.inspect(|expression| {
|
.inspect(|expression| {
|
||||||
if expression.is_none() {
|
if expression.is_none() {
|
||||||
panic!("Attempt to pass non-expression")
|
panic!("Attempt to pass non-expression")
|
||||||
@ -183,21 +236,17 @@ impl Call {
|
|||||||
})
|
})
|
||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
.collect();
|
.collect();
|
||||||
let callable_symbol = self.get_callee_symbol();
|
let callable_symbol = self.get_callee_symbol(symbol_table);
|
||||||
match callable_symbol {
|
match callable_symbol {
|
||||||
CallableSymbol::Function(function_symbol) => IrCall::new(
|
CallableSymbol::Function(function_symbol) => IrCall::new(
|
||||||
fqn_parts_to_string(function_symbol.borrow().fqn_parts()),
|
fqn_parts_to_string(function_symbol.fqn_parts()),
|
||||||
arguments,
|
arguments,
|
||||||
function_symbol.borrow().is_extern(),
|
function_symbol.is_extern(),
|
||||||
),
|
),
|
||||||
CallableSymbol::Class(class_symbol) => {
|
CallableSymbol::Class(class_symbol) => {
|
||||||
let constructor_symbol = class_symbol
|
let constructor_symbol = class_symbol.constructor_symbol();
|
||||||
.borrow()
|
|
||||||
.constructor_symbol()
|
|
||||||
.cloned()
|
|
||||||
.expect("Default constructors not supported yet.");
|
|
||||||
IrCall::new(
|
IrCall::new(
|
||||||
fqn_parts_to_string(constructor_symbol.borrow().fqn_parts()),
|
fqn_parts_to_string(constructor_symbol.fqn_parts()),
|
||||||
arguments,
|
arguments,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,24 +6,21 @@ use crate::ast::fqn_context::FqnContext;
|
|||||||
use crate::ast::fqn_util::fqn_parts_to_string;
|
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::{
|
use crate::ast::helpers::{collect_diagnostics_mut, collect_diagnostics_single, resolve_ctor_name};
|
||||||
collect_diagnostics_mut, collect_diagnostics_single, map_symbol_insert_result,
|
|
||||||
resolve_ctor_name,
|
|
||||||
};
|
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT};
|
use crate::error_codes::{FIELD_MULTIPLE_INIT, FIELD_UNINIT};
|
||||||
use crate::ir::ir_class::{IrClass, IrField};
|
use crate::ir::ir_class::{IrClass, IrField};
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
|
use crate::ok_or_err_diagnostics;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::{ok_or_err_diagnostics, push_ok_or_push_errs};
|
use crate::type_info::TypeInfo;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use crate::types_table::TypesTable;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -34,7 +31,7 @@ pub struct Class {
|
|||||||
constructor: Option<Constructor>,
|
constructor: Option<Constructor>,
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
class_symbol: Option<Rc<RefCell<ClassSymbol>>>,
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Class {
|
impl Class {
|
||||||
@ -53,258 +50,146 @@ impl Class {
|
|||||||
constructor,
|
constructor,
|
||||||
fields,
|
fields,
|
||||||
functions,
|
functions,
|
||||||
class_symbol: None,
|
scope_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a [ClassSymbol] representing this class.
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
fn make_class_symbol(&self, fqn_context: &FqnContext) -> ClassSymbol {
|
self.scope_id = Some(container_scope);
|
||||||
ClassSymbol::new(
|
|
||||||
&self.declared_name,
|
|
||||||
self.declared_name_source_range.clone(),
|
|
||||||
fqn_context.resolve(&self.declared_name),
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts the given [ClassSymbol] into the `symbol_table`, returning `Ok` if the insert was
|
let class_scope =
|
||||||
/// successful, else `Err` with diagnostics.
|
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
||||||
fn insert_class_symbol(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
class_symbol: ClassSymbol,
|
|
||||||
) -> Result<Rc<RefCell<ClassSymbol>>, Vec<Diagnostic>> {
|
|
||||||
map_symbol_insert_result(
|
|
||||||
symbol_table.insert_class_symbol(class_symbol),
|
|
||||||
&self.declared_name_source_range,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets this class' class symbol to the given symbol.
|
|
||||||
fn set_class_symbol(&mut self, symbol: Rc<RefCell<ClassSymbol>>) {
|
|
||||||
self.class_symbol = Some(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers names of this class' generic parameters, returning `Ok` if all
|
|
||||||
/// [GenericParameter]s produced an `Ok(GenericParameterSymbol)`, else `Err`.
|
|
||||||
fn gather_generic_parameters_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<Vec<Rc<RefCell<GenericParameterSymbol>>>, Vec<Diagnostic>> {
|
|
||||||
let mut symbols: Vec<Rc<RefCell<GenericParameterSymbol>>> = vec![];
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
for generic_parameter in &mut self.generic_parameters {
|
for generic_parameter in &mut self.generic_parameters {
|
||||||
push_ok_or_push_errs!(
|
generic_parameter.init_scopes(symbol_table, class_scope);
|
||||||
generic_parameter.gather_declared_names(symbol_table),
|
|
||||||
symbols,
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ok_or_err_diagnostics!(symbols, diagnostics)
|
let class_body_scope =
|
||||||
}
|
symbol_table.push_class_scope(&format!("class_body_scope({})", self.declared_name));
|
||||||
|
|
||||||
/// Returns a [Ref] to this class' [ClassSymbol]. Only safe to call if the class symbol has been
|
for field in &mut self.fields {
|
||||||
/// set.
|
field.init_scopes(symbol_table, class_body_scope);
|
||||||
fn use_class_symbol(&self) -> Ref<ClassSymbol> {
|
|
||||||
self.class_symbol.as_ref().unwrap().borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a [RefMut] to this class' [ClassSymbol]. Only safe to call if the class symbol has
|
|
||||||
/// been set.
|
|
||||||
fn use_class_symbol_mut(&mut self) -> RefMut<ClassSymbol> {
|
|
||||||
self.class_symbol.as_mut().unwrap().borrow_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the given [GenericParameterSymbol]s on this class' [ClassSymbol].
|
|
||||||
fn set_generic_parameters_on_class_symbol(
|
|
||||||
&mut self,
|
|
||||||
generic_parameter_symbols: Vec<Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
) {
|
|
||||||
self.use_class_symbol_mut()
|
|
||||||
.set_generic_parameters(generic_parameter_symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `Ok` of [FieldSymbol]s if all of this class' fields [Field::gather_declared_names]
|
|
||||||
/// methods return `Ok`, else `Err` of [Diagnostic]s.
|
|
||||||
fn gather_fields_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<Vec<Rc<RefCell<FieldSymbol>>>, Vec<Diagnostic>> {
|
|
||||||
let mut symbols: Vec<Rc<RefCell<FieldSymbol>>> = vec![];
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
for (field_index, field) in self.fields.iter_mut().enumerate() {
|
|
||||||
push_ok_or_push_errs!(
|
|
||||||
field.gather_declared_names(symbol_table, field_index),
|
|
||||||
symbols,
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ok_or_err_diagnostics!(symbols, diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the given `field_symbols` [Vec] into a [HashMap] of field names to [FieldSymbol]s.
|
|
||||||
fn make_fields_hash_map(
|
|
||||||
field_symbols: Vec<Rc<RefCell<FieldSymbol>>>,
|
|
||||||
) -> HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
|
||||||
HashMap::from_iter(
|
|
||||||
field_symbols
|
|
||||||
.into_iter()
|
|
||||||
.map(|field| {
|
|
||||||
let name = field.borrow().declared_name_owned();
|
|
||||||
(name, field)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the field symbols property on the class' [ClassSymbol].
|
|
||||||
fn set_field_symbols_on_class_symbol(&mut self, field_symbols: Vec<Rc<RefCell<FieldSymbol>>>) {
|
|
||||||
self.use_class_symbol_mut()
|
|
||||||
.set_fields(Self::make_fields_hash_map(field_symbols))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a [ConstructorSymbol] representing a default constructor appropriate for this class.
|
|
||||||
fn make_default_constructor(&self, fqn_context: &FqnContext) -> ConstructorSymbol {
|
|
||||||
ConstructorSymbol::new(
|
|
||||||
self.declared_name_source_range.clone(),
|
|
||||||
resolve_ctor_name(fqn_context),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers names in the class' [Constructor] and returns a [ConstructorSymbol], if the
|
|
||||||
/// constructor is present; else returns a symbol defining a default constructor.
|
|
||||||
fn gather_constructor_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
|
||||||
) -> Result<Rc<RefCell<ConstructorSymbol>>, Vec<Diagnostic>> {
|
|
||||||
if let Some(constructor) = &mut self.constructor {
|
if let Some(constructor) = &mut self.constructor {
|
||||||
constructor.gather_declared_names(symbol_table, fqn_context)
|
constructor.init_scopes(symbol_table, class_body_scope);
|
||||||
} else {
|
}
|
||||||
Ok(Rc::new(RefCell::new(
|
for function in &mut self.functions {
|
||||||
self.make_default_constructor(fqn_context),
|
function.init_scopes(symbol_table, class_body_scope);
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the constructor symbol on this class' [ClassSymbol].
|
|
||||||
fn set_constructor_symbol_on_class_symbol(
|
|
||||||
&mut self,
|
|
||||||
constructor_symbol: Rc<RefCell<ConstructorSymbol>>,
|
|
||||||
) {
|
|
||||||
self.use_class_symbol_mut()
|
|
||||||
.set_constructor_symbol(constructor_symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers function names and returns `Ok` if no diagnostics, else `Err`.
|
|
||||||
fn gather_functions_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
collect_diagnostics_mut(&mut self.functions, |f| {
|
|
||||||
f.gather_declared_names(symbol_table, fqn_context, self.class_symbol.as_ref())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &mut FqnContext,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
// 1. Make and insert class symbol
|
|
||||||
let to_insert = self.make_class_symbol(fqn_context);
|
|
||||||
let class_symbol = self.insert_class_symbol(symbol_table, to_insert)?;
|
|
||||||
self.set_class_symbol(class_symbol);
|
|
||||||
|
|
||||||
// 2. Push class name on fqn context
|
|
||||||
fqn_context.push(self.declared_name.clone());
|
|
||||||
|
|
||||||
// 3. push scope
|
|
||||||
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
|
||||||
|
|
||||||
// 4. gather generic parameters
|
|
||||||
let generic_parameter_symbols = self
|
|
||||||
.gather_generic_parameters_names(symbol_table)
|
|
||||||
.inspect_err(|_| {
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
fqn_context.pop();
|
|
||||||
})?;
|
|
||||||
self.set_generic_parameters_on_class_symbol(generic_parameter_symbols);
|
|
||||||
|
|
||||||
// 5. gather fields
|
|
||||||
let field_symbols = self.gather_fields_names(symbol_table).inspect_err(|_| {
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
fqn_context.pop();
|
|
||||||
})?;
|
|
||||||
self.set_field_symbols_on_class_symbol(field_symbols);
|
|
||||||
|
|
||||||
// 6. gather constructor
|
|
||||||
let constructor_symbol = self
|
|
||||||
.gather_constructor_names(symbol_table, fqn_context)
|
|
||||||
.inspect_err(|_| {
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
fqn_context.pop();
|
|
||||||
})?;
|
|
||||||
self.set_constructor_symbol_on_class_symbol(constructor_symbol);
|
|
||||||
|
|
||||||
// 7. gather functions
|
|
||||||
self.gather_functions_names(symbol_table, fqn_context)
|
|
||||||
.inspect_err(|_| {
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
fqn_context.pop();
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// 8. pop scope
|
|
||||||
symbol_table.pop_scope();
|
symbol_table.pop_scope();
|
||||||
|
symbol_table.pop_scope();
|
||||||
// 9. pop fqn part
|
|
||||||
fqn_context.pop();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_generics_names(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn make_symbols(&self, fqn_context: &mut FqnContext) -> Vec<Symbol> {
|
||||||
collect_diagnostics_mut(&mut self.generic_parameters, |gp| {
|
let mut all_symbols: Vec<Symbol> = Vec::new();
|
||||||
gp.check_name_usages(symbol_table, self.class_symbol.as_ref())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks the [Constructor]'s name usages if present.
|
let mut generic_parameter_symbols = Vec::new();
|
||||||
fn check_constructor_names(
|
for generic_parameter in &self.generic_parameters {
|
||||||
&mut self,
|
let symbol = Rc::new(generic_parameter.make_symbol());
|
||||||
symbol_table: &SymbolTable,
|
all_symbols.push(Symbol::GenericParameter(symbol.clone()));
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
generic_parameter_symbols.push(symbol);
|
||||||
if let Some(constructor) = &mut self.constructor {
|
|
||||||
constructor.check_name_usages(symbol_table, self.class_symbol.as_ref())?
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
let mut field_symbols = Vec::new();
|
||||||
|
for field in &self.fields {
|
||||||
|
let symbol = Rc::new(field.make_symbol());
|
||||||
|
all_symbols.push(Symbol::Field(symbol.clone()));
|
||||||
|
field_symbols.push(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
fqn_context.push(self.declared_name.clone()); // namespace this class' members
|
||||||
|
|
||||||
|
let constructor_symbol = if let Some(constructor) = &self.constructor {
|
||||||
|
let (constructor_symbol, mut symbols) = constructor.make_symbols(fqn_context);
|
||||||
|
all_symbols.append(&mut symbols);
|
||||||
|
constructor_symbol
|
||||||
|
} else {
|
||||||
|
Rc::new(ConstructorSymbol::new(
|
||||||
|
&self.declared_name_source_range,
|
||||||
|
resolve_ctor_name(fqn_context),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
self.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.make_symbols(fqn_context, true);
|
||||||
|
all_symbols.append(&mut symbols);
|
||||||
|
function_symbols.push(function_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
fqn_context.pop(); // un-namespace
|
||||||
|
|
||||||
|
let class_symbol = Rc::new(ClassSymbol::new(
|
||||||
|
&self.declared_name,
|
||||||
|
&self.declared_name_source_range,
|
||||||
|
fqn_context.resolve(&self.declared_name),
|
||||||
|
false,
|
||||||
|
self.scope_id.unwrap(),
|
||||||
|
generic_parameter_symbols,
|
||||||
|
constructor_symbol,
|
||||||
|
field_symbols,
|
||||||
|
function_symbols,
|
||||||
|
));
|
||||||
|
all_symbols.push(Symbol::Class(class_symbol.clone()));
|
||||||
|
|
||||||
|
all_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fields_names(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
collect_diagnostics_mut(&mut self.fields, |f| {
|
let mut diagnostics: Vec<Diagnostic> = Vec::new();
|
||||||
f.check_name_usages(symbol_table, self.class_symbol.as_ref())
|
|
||||||
})
|
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 check_functions_names(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_field_initializer_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
collect_diagnostics_mut(&mut self.functions, |f| {
|
let class_symbol = symbol_table
|
||||||
f.check_name_usages(symbol_table, self.class_symbol.as_ref())
|
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
|
||||||
})
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
self.fields
|
||||||
|
.iter()
|
||||||
|
.flat_map(|field| field.check_field_initializer_names(symbol_table, &class_symbol))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn analyze_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
self.check_generics_names(symbol_table)?;
|
let class_symbol = symbol_table
|
||||||
self.check_constructor_names(symbol_table)?;
|
.get_class_symbol(self.scope_id.unwrap(), &self.declared_name)
|
||||||
self.check_fields_names(symbol_table)?;
|
.cloned()
|
||||||
self.check_functions_names(symbol_table)?;
|
.unwrap();
|
||||||
Ok(())
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_check_generics(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
fn type_check_generics(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
@ -313,22 +198,35 @@ impl Class {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_check_fields(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
fn type_check_fields(
|
||||||
collect_diagnostics_mut(&mut self.fields, |f| f.type_check(symbol_table))
|
&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(
|
fn type_check_constructor(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
if let Some(constructor) = &mut self.constructor {
|
if let Some(constructor) = &mut self.constructor {
|
||||||
constructor.type_check(symbol_table)?;
|
constructor.type_check(symbol_table, types_table)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_check_functions(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
fn type_check_functions(
|
||||||
collect_diagnostics_mut(&mut self.functions, |f| f.type_check(symbol_table))
|
&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.
|
/// Returns all field names with declared initializers.
|
||||||
@ -350,16 +248,14 @@ impl Class {
|
|||||||
&self,
|
&self,
|
||||||
assign_statement: &'a AssignStatement,
|
assign_statement: &'a AssignStatement,
|
||||||
fields_already_init: &HashSet<&&str>,
|
fields_already_init: &HashSet<&&str>,
|
||||||
|
class_symbol: &ClassSymbol,
|
||||||
) -> Result<Option<&'a str>, Diagnostic> {
|
) -> Result<Option<&'a str>, Diagnostic> {
|
||||||
match assign_statement.destination() {
|
match assign_statement.destination() {
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
// find matching field symbol, if there is one
|
// find matching field symbol, if there is one
|
||||||
if let Some(field_symbol) = self.use_class_symbol().fields().get(identifier.name())
|
if let Some(field_symbol) = class_symbol.fields().get(identifier.name()) {
|
||||||
{
|
|
||||||
// check that we don't init more than once IF field is immutable
|
// check that we don't init more than once IF field is immutable
|
||||||
if fields_already_init.contains(&identifier.name())
|
if fields_already_init.contains(&identifier.name()) && !field_symbol.is_mut() {
|
||||||
&& !field_symbol.borrow().is_mut()
|
|
||||||
{
|
|
||||||
let diagnostic = Diagnostic::new(
|
let diagnostic = Diagnostic::new(
|
||||||
&format!("Immutable field {} cannot be initialized more than once in constructor.", identifier.name()),
|
&format!("Immutable field {} cannot be initialized more than once in constructor.", identifier.name()),
|
||||||
identifier.source_range().start(),
|
identifier.source_range().start(),
|
||||||
@ -388,19 +284,25 @@ impl Class {
|
|||||||
fn get_fields_init_in_ctor<'a>(
|
fn get_fields_init_in_ctor<'a>(
|
||||||
&self,
|
&self,
|
||||||
fields_with_declared_initializers: &HashSet<&str>,
|
fields_with_declared_initializers: &HashSet<&str>,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
) -> Result<HashSet<&str>, Vec<Diagnostic>> {
|
) -> Result<HashSet<&str>, Vec<Diagnostic>> {
|
||||||
let mut constructor_inits: HashSet<&str> = HashSet::new();
|
let mut constructor_inits: HashSet<&str> = HashSet::new();
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
if let Some(constructor) = &self.constructor {
|
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() {
|
for statement in constructor.statements() {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Assign(assign_statement) => {
|
Statement::Assign(assign_statement) => {
|
||||||
let fields_init_so_far = constructor_inits
|
let fields_init_so_far = constructor_inits
|
||||||
.union(fields_with_declared_initializers)
|
.union(fields_with_declared_initializers)
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
match self
|
match self.check_ctor_assign_statement(
|
||||||
.check_ctor_assign_statement(assign_statement, &fields_init_so_far)
|
assign_statement,
|
||||||
{
|
&fields_init_so_far,
|
||||||
|
&class_symbol,
|
||||||
|
) {
|
||||||
Ok(maybe_init_field) => match maybe_init_field {
|
Ok(maybe_init_field) => match maybe_init_field {
|
||||||
None => {}
|
None => {}
|
||||||
Some(init_field) => {
|
Some(init_field) => {
|
||||||
@ -445,14 +347,17 @@ impl Class {
|
|||||||
/// Immutable fields may be only initialized once, either at their declaration or once in the
|
/// 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
|
/// constructor. Mutable fields may be initialized either at their declaration, or at least once
|
||||||
/// in the constructor.
|
/// in the constructor.
|
||||||
fn check_field_initialization(&self) -> Result<(), Vec<Diagnostic>> {
|
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).
|
// 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
|
// 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
|
// are fields <- initialized by constructor. Then circle back to fields and check all are
|
||||||
// initialized
|
// initialized
|
||||||
let field_names_with_initializers = self.field_names_with_initializers();
|
let field_names_with_initializers = self.field_names_with_initializers();
|
||||||
let field_names_init_in_constructor =
|
let field_names_init_in_constructor =
|
||||||
self.get_fields_init_in_ctor(&field_names_with_initializers)?;
|
self.get_fields_init_in_ctor(&field_names_with_initializers, symbol_table)?;
|
||||||
let combined = field_names_with_initializers
|
let combined = field_names_with_initializers
|
||||||
.union(&field_names_init_in_constructor)
|
.union(&field_names_init_in_constructor)
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
@ -463,35 +368,45 @@ impl Class {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.type_check_generics(symbol_table)?;
|
self.type_check_generics(symbol_table)?;
|
||||||
self.type_check_fields(symbol_table)?;
|
self.type_check_fields(symbol_table, types_table)?;
|
||||||
self.type_check_constructor(symbol_table)?;
|
self.type_check_constructor(symbol_table, types_table)?;
|
||||||
self.type_check_functions(symbol_table)?;
|
self.type_check_functions(symbol_table, types_table)?;
|
||||||
self.check_field_initialization()?;
|
self.check_field_initialization(symbol_table)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> (IrClass, Vec<IrFunction>) {
|
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![];
|
let mut ir_functions: Vec<IrFunction> = vec![];
|
||||||
if let Some(constructor) = &self.constructor {
|
if let Some(constructor) = &self.constructor {
|
||||||
ir_functions.push(constructor.to_ir(
|
ir_functions.push(constructor.to_ir(
|
||||||
self.class_symbol.as_ref().unwrap(),
|
self_class_symbol,
|
||||||
&self.fields,
|
&self.fields,
|
||||||
symbol_table,
|
symbol_table,
|
||||||
|
types_table,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
ir_functions
|
ir_functions.push(function.to_ir(symbol_table, types_table, Some(self_class_symbol)));
|
||||||
.push(function.to_ir(symbol_table, Some(self.class_symbol.as_ref().unwrap())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_symbol = self.class_symbol.as_ref().unwrap().borrow();
|
|
||||||
|
|
||||||
let ir_class = IrClass::new(
|
let ir_class = IrClass::new(
|
||||||
class_symbol.declared_name_owned(),
|
self_class_symbol.declared_name_owned(),
|
||||||
fqn_parts_to_string(class_symbol.fqn_parts()).into(),
|
fqn_parts_to_string(self_class_symbol.fqn_parts()).into(),
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
|
|||||||
@ -2,12 +2,13 @@ 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::fqn_context::FqnContext;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::helpers::collect_diagnostics_into_mut;
|
use crate::ast::helpers::{collect_diagnostics_into_mut, try_insert_symbols_into};
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::diagnostics_result;
|
|
||||||
use crate::ir::ir_class::IrClass;
|
use crate::ir::ir_class::IrClass;
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
use crate::{diagnostics_result, handle_diagnostics};
|
||||||
|
|
||||||
pub struct CompilationUnit {
|
pub struct CompilationUnit {
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
@ -40,68 +41,70 @@ impl CompilationUnit {
|
|||||||
&self.classes
|
&self.classes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable) {
|
||||||
&mut self,
|
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 gather_symbols_into(
|
||||||
|
&self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
symbol_table.push_module_scope("compilation_unit_scope");
|
let mut diagnostics = vec![];
|
||||||
|
let mut fqn_context = FqnContext::new();
|
||||||
let mut fqn_context = FqnContext::new(); // in the future, we'll push the pkg/ns on here
|
for class in &self.classes {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
handle_diagnostics!(
|
||||||
|
try_insert_symbols_into(class.make_symbols(&mut fqn_context), symbol_table),
|
||||||
collect_diagnostics_into_mut(
|
diagnostics
|
||||||
&mut self.functions,
|
);
|
||||||
|f| f.gather_declared_names(symbol_table, &fqn_context, None),
|
}
|
||||||
&mut diagnostics,
|
for function in &self.functions {
|
||||||
);
|
let (_, symbols) = function.make_symbols(&mut fqn_context, false);
|
||||||
|
handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics);
|
||||||
collect_diagnostics_into_mut(
|
}
|
||||||
&mut self.extern_functions,
|
for extern_function in &self.extern_functions {
|
||||||
|ef| ef.gather_declared_names(symbol_table, &fqn_context),
|
let (_, symbols) = extern_function.make_symbols(&mut fqn_context);
|
||||||
&mut diagnostics,
|
handle_diagnostics!(try_insert_symbols_into(symbols, symbol_table), diagnostics);
|
||||||
);
|
}
|
||||||
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
&mut self.classes,
|
|
||||||
|c| c.gather_declared_names(symbol_table, &mut fqn_context),
|
|
||||||
&mut diagnostics,
|
|
||||||
);
|
|
||||||
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
diagnostics_result!(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_names(&self, symbol_table: &mut SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
for class in &self.classes {
|
||||||
collect_diagnostics_into_mut(
|
diagnostics.append(&mut class.check_names(symbol_table));
|
||||||
&mut self.functions,
|
diagnostics.append(&mut class.check_field_initializer_names(symbol_table));
|
||||||
|f| f.check_name_usages(symbol_table, None),
|
diagnostics.append(&mut class.analyze_local_names(symbol_table));
|
||||||
&mut diagnostics,
|
}
|
||||||
);
|
for function in &self.functions {
|
||||||
|
diagnostics.append(&mut function.check_names(symbol_table));
|
||||||
collect_diagnostics_into_mut(
|
diagnostics.append(&mut function.analyze_static_fn_local_names(symbol_table));
|
||||||
&mut self.extern_functions,
|
}
|
||||||
|ef| ef.check_name_usages(symbol_table, None),
|
for extern_function in &self.extern_functions {
|
||||||
&mut diagnostics,
|
diagnostics.append(&mut extern_function.check_names(symbol_table));
|
||||||
);
|
}
|
||||||
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
&mut self.classes,
|
|
||||||
|c| c.check_name_usages(symbol_table),
|
|
||||||
&mut diagnostics,
|
|
||||||
);
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
diagnostics_result!(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
collect_diagnostics_into_mut(
|
collect_diagnostics_into_mut(
|
||||||
&mut self.functions,
|
&mut self.functions,
|
||||||
|f| f.type_check(symbol_table),
|
|f| f.type_check(symbol_table, types_table),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -113,24 +116,28 @@ impl CompilationUnit {
|
|||||||
|
|
||||||
collect_diagnostics_into_mut(
|
collect_diagnostics_into_mut(
|
||||||
&mut self.classes,
|
&mut self.classes,
|
||||||
|c| c.type_check(symbol_table),
|
|c| c.type_check(symbol_table, types_table),
|
||||||
&mut diagnostics,
|
&mut diagnostics,
|
||||||
);
|
);
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
diagnostics_result!(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, symbol_table: &SymbolTable) -> (Vec<IrClass>, Vec<IrFunction>) {
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) -> (Vec<IrClass>, Vec<IrFunction>) {
|
||||||
let mut functions: Vec<IrFunction> = vec![];
|
let mut functions: Vec<IrFunction> = vec![];
|
||||||
let mut classes: Vec<IrClass> = vec![];
|
let mut classes: Vec<IrClass> = vec![];
|
||||||
|
|
||||||
self.functions
|
self.functions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| f.to_ir(symbol_table, None))
|
.map(|f| f.to_ir(symbol_table, types_table, None))
|
||||||
.for_each(|f| functions.push(f));
|
.for_each(|f| functions.push(f));
|
||||||
|
|
||||||
for class in &self.classes {
|
for class in &self.classes {
|
||||||
let (class, mut class_functions) = class.to_ir(symbol_table);
|
let (class, mut class_functions) = class.to_ir(symbol_table, types_table);
|
||||||
functions.append(&mut class_functions);
|
functions.append(&mut class_functions);
|
||||||
classes.push(class);
|
classes.push(class);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::ast::field::Field;
|
use crate::ast::field::Field;
|
||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::fqn_util::fqn_parts_to_string;
|
use crate::ast::fqn_util::fqn_parts_to_string;
|
||||||
use crate::ast::helpers::resolve_ctor_name;
|
use crate::ast::helpers::{collect_parameter_symbols_into, resolve_ctor_name};
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
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;
|
||||||
@ -22,9 +22,9 @@ use crate::source_range::SourceRange;
|
|||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -34,6 +34,7 @@ pub struct Constructor {
|
|||||||
ctor_keyword_source_range: SourceRange,
|
ctor_keyword_source_range: SourceRange,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constructor {
|
impl Constructor {
|
||||||
@ -48,6 +49,7 @@ impl Constructor {
|
|||||||
ctor_keyword_source_range,
|
ctor_keyword_source_range,
|
||||||
parameters,
|
parameters,
|
||||||
statements,
|
statements,
|
||||||
|
scope_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,112 +57,67 @@ impl Constructor {
|
|||||||
&self.statements
|
&self.statements
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.scope_id = Some(container_scope);
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
let function_scope = symbol_table.push_function_scope("constructor_scope");
|
||||||
) -> Result<Rc<RefCell<ConstructorSymbol>>, Vec<Diagnostic>> {
|
|
||||||
// insert constructor symbol
|
for parameter in &mut self.parameters {
|
||||||
let to_insert = ConstructorSymbol::new(
|
parameter.init_scopes(symbol_table, function_scope);
|
||||||
self.ctor_keyword_source_range.clone(),
|
}
|
||||||
|
|
||||||
|
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),
|
resolve_ctor_name(fqn_context),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
self.scope_id.unwrap(),
|
||||||
let constructor_symbol =
|
parameter_symbols,
|
||||||
symbol_table
|
));
|
||||||
.insert_constructor_symbol(to_insert)
|
all_symbols.push(Symbol::Constructor(constructor_symbol.clone()));
|
||||||
.map_err(|symbol_insert_error| match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(_) => {
|
|
||||||
vec![
|
|
||||||
Diagnostic::new(
|
|
||||||
"Cannot declare more than one constructor.",
|
|
||||||
self.ctor_keyword_source_range.start(),
|
|
||||||
self.ctor_keyword_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!()),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
symbol_table.push_function_scope("ctor_scope");
|
(constructor_symbol, all_symbols)
|
||||||
|
|
||||||
let mut parameter_symbols: Vec<Rc<RefCell<ParameterSymbol>>> = vec![];
|
|
||||||
let mut parameters_diagnostics = vec![];
|
|
||||||
|
|
||||||
for parameter in &mut self.parameters {
|
|
||||||
match parameter.gather_declared_names(symbol_table) {
|
|
||||||
Ok(parameter_symbol) => {
|
|
||||||
parameter_symbols.push(parameter_symbol);
|
|
||||||
}
|
|
||||||
Err(mut ds) => {
|
|
||||||
parameters_diagnostics.append(&mut ds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !parameters_diagnostics.is_empty() {
|
|
||||||
symbol_table.pop_scope();
|
|
||||||
return Err(parameters_diagnostics);
|
|
||||||
} else {
|
|
||||||
constructor_symbol
|
|
||||||
.borrow_mut()
|
|
||||||
.set_parameters(parameter_symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol_table.push_block_scope("ctor_main_block");
|
|
||||||
|
|
||||||
let statements_diagnostics = self
|
|
||||||
.statements
|
|
||||||
.iter_mut()
|
|
||||||
.map(|stmt| stmt.gather_declared_names(symbol_table))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
symbol_table.pop_scope(); // block
|
|
||||||
symbol_table.pop_scope(); // function
|
|
||||||
|
|
||||||
if statements_diagnostics.is_empty() {
|
|
||||||
Ok(constructor_symbol)
|
|
||||||
} else {
|
|
||||||
Err(statements_diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
types_table: &mut TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let parameters_diagnostics: Vec<Diagnostic> = self
|
|
||||||
.parameters
|
|
||||||
.iter_mut()
|
|
||||||
.map(|param| param.check_name_usages(symbol_table, class_context))
|
|
||||||
.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.check_name_usages(symbol_table))
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if statements_diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(statements_diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let parameters_diagnostics: Vec<Diagnostic> = self
|
let parameters_diagnostics: Vec<Diagnostic> = self
|
||||||
.parameters
|
.parameters
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -176,7 +133,7 @@ impl Constructor {
|
|||||||
let statements_diagnostics: Vec<Diagnostic> = self
|
let statements_diagnostics: Vec<Diagnostic> = self
|
||||||
.statements
|
.statements
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|statement| statement.type_check(symbol_table, None))
|
.map(|statement| statement.type_check(symbol_table, types_table, None))
|
||||||
.filter_map(Result::err)
|
.filter_map(Result::err)
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
@ -190,9 +147,10 @@ impl Constructor {
|
|||||||
|
|
||||||
pub fn to_ir(
|
pub fn to_ir(
|
||||||
&self,
|
&self,
|
||||||
class_symbol: &Rc<RefCell<ClassSymbol>>,
|
class_symbol: &Rc<ClassSymbol>,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> IrFunction {
|
) -> IrFunction {
|
||||||
let mut ir_builder = IrBuilder::new();
|
let mut ir_builder = IrBuilder::new();
|
||||||
|
|
||||||
@ -202,17 +160,22 @@ impl Constructor {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, parameter)| {
|
.map(|(i, parameter)| {
|
||||||
let mut parameter_symbol = parameter.parameter_symbol().borrow_mut();
|
let parameter_symbol = symbol_table
|
||||||
|
.get_parameter_symbol_owned(parameter.scope_id(), parameter.declared_name())
|
||||||
|
.unwrap();
|
||||||
|
let parameter_type = types_table
|
||||||
|
.parameter_types()
|
||||||
|
.get(¶meter_symbol)
|
||||||
|
.unwrap();
|
||||||
let offset = (parameters_count as isize).neg() + i as isize;
|
let offset = (parameters_count as isize).neg() + i as isize;
|
||||||
let ir_parameter = Rc::new(IrParameter::new(
|
let ir_parameter = Rc::new(IrParameter::new(
|
||||||
parameter_symbol.declared_name(),
|
parameter_symbol.declared_name(),
|
||||||
parameter_symbol.type_info().clone(),
|
parameter_type.clone(),
|
||||||
offset,
|
offset,
|
||||||
));
|
));
|
||||||
|
|
||||||
// make sure to save ir_parameter to symbol so others can access it
|
// make sure to save ir_parameter to symbol so others can access it
|
||||||
let to_save = ir_parameter.clone();
|
ir_builder.push_parameter(¶meter_symbol, ir_parameter.clone());
|
||||||
parameter_symbol.set_ir_parameter(to_save);
|
|
||||||
|
|
||||||
ir_parameter
|
ir_parameter
|
||||||
})
|
})
|
||||||
@ -234,7 +197,7 @@ impl Constructor {
|
|||||||
|
|
||||||
let alloc_assign = IrAssign::new(
|
let alloc_assign = IrAssign::new(
|
||||||
self_variable.clone(),
|
self_variable.clone(),
|
||||||
IrOperation::Allocate(IrAllocate::new(class_symbol.borrow().declared_name_owned())),
|
IrOperation::Allocate(IrAllocate::new(class_symbol.declared_name_owned())),
|
||||||
);
|
);
|
||||||
ir_builder
|
ir_builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
@ -275,7 +238,7 @@ impl Constructor {
|
|||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let ir_expression = initializer
|
let ir_expression = initializer
|
||||||
.to_ir_expression(&mut ir_builder, symbol_table)
|
.to_ir_expression(&mut ir_builder, symbol_table, types_table)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ir_set_field = IrSetField::new(
|
let ir_set_field = IrSetField::new(
|
||||||
&field_mut_ref_variable, // dumb that we clone it and then ref it
|
&field_mut_ref_variable, // dumb that we clone it and then ref it
|
||||||
@ -289,7 +252,7 @@ impl Constructor {
|
|||||||
|
|
||||||
// do "declared" statements of constructor
|
// do "declared" statements of constructor
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.to_ir(&mut ir_builder, symbol_table, false);
|
statement.to_ir(&mut ir_builder, symbol_table, types_table, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return complete self object
|
// return complete self object
|
||||||
@ -303,16 +266,12 @@ impl Constructor {
|
|||||||
ir_builder.finish_block();
|
ir_builder.finish_block();
|
||||||
let entry_block = ir_builder.get_block(entry_block_id);
|
let entry_block = ir_builder.get_block(entry_block_id);
|
||||||
|
|
||||||
|
let constructor_symbol = symbol_table
|
||||||
|
.get_constructor_symbol(self.scope_id.unwrap())
|
||||||
|
.unwrap();
|
||||||
IrFunction::new(
|
IrFunction::new(
|
||||||
fqn_parts_to_string(
|
fqn_parts_to_string(constructor_symbol.fqn_parts()),
|
||||||
class_symbol
|
ir_parameters,
|
||||||
.borrow()
|
|
||||||
.constructor_symbol()
|
|
||||||
.unwrap()
|
|
||||||
.borrow()
|
|
||||||
.fqn_parts(),
|
|
||||||
), // fake function symbol
|
|
||||||
&ir_parameters, // make params
|
|
||||||
&TypeInfo::ClassInstance(class_symbol.clone()),
|
&TypeInfo::ClassInstance(class_symbol.clone()),
|
||||||
entry_block.clone(),
|
entry_block.clone(),
|
||||||
)
|
)
|
||||||
|
|||||||
88
dmc-lib/src/ast/diagnostic_factories.rs
Normal file
88
dmc-lib/src/ast/diagnostic_factories.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
||||||
|
use crate::error_codes::{
|
||||||
|
OUTER_CLASS_FIELD_USED_IN_INIT, OUTER_CLASS_METHOD_USED_IN_INIT, SELF_CONSTRUCTOR_USED_IN_INIT,
|
||||||
|
SELF_FIELD_USED_IN_INIT, SELF_METHOD_USED_IN_INIT, SYMBOL_ALREADY_DECLARED, SYMBOL_NOT_FOUND,
|
||||||
|
};
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol::Symbol;
|
||||||
|
|
||||||
|
pub fn symbol_not_found(name: &str, source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
&format!("Symbol {} not found in scope.", name),
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SYMBOL_NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cannot_reference_field_in_init(name: &str, source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
&format!("Cannot reference field {} during initialization.", name),
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SELF_FIELD_USED_IN_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol_already_declared(already_inserted: &Symbol, would_insert: &Symbol) -> Diagnostic {
|
||||||
|
let secondary_label = SecondaryLabel::new(
|
||||||
|
already_inserted.declared_name_source_range().start(),
|
||||||
|
already_inserted.declared_name_source_range().end(),
|
||||||
|
Some("Symbol already declared here.".to_string()),
|
||||||
|
);
|
||||||
|
Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Symbol {} already declared in current scope.",
|
||||||
|
would_insert.declared_name()
|
||||||
|
),
|
||||||
|
would_insert.declared_name_source_range().start(),
|
||||||
|
would_insert.declared_name_source_range().end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SYMBOL_ALREADY_DECLARED)
|
||||||
|
.with_secondary_labels(&[secondary_label])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn self_constructor_used_in_init(source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"Cannot call Self constructor during initialization.",
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SELF_CONSTRUCTOR_USED_IN_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn self_field_used_in_init(source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"Cannot reference Self field during initialization.",
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SELF_FIELD_USED_IN_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn self_method_used_in_init(source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"Cannot call Self method during initialization.",
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(SELF_METHOD_USED_IN_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outer_class_field_usage(source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"Cannot reference an outer class member.",
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(OUTER_CLASS_FIELD_USED_IN_INIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outer_class_method_usage(source_range: &SourceRange) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"Cannot call an outer class method.",
|
||||||
|
source_range.start(),
|
||||||
|
source_range.end(),
|
||||||
|
)
|
||||||
|
.with_error_code(OUTER_CLASS_METHOD_USED_IN_INIT)
|
||||||
|
}
|
||||||
@ -13,8 +13,10 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
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::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -29,61 +31,164 @@ pub enum Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn gather_declared_names(
|
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 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![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Binary(binary_expression) => {
|
Expression::Binary(binary_expression) => {
|
||||||
binary_expression.gather_declared_names(symbol_table)
|
binary_expression.type_check(symbol_table, types_table)
|
||||||
}
|
}
|
||||||
Expression::Negative(negative_expression) => {
|
Expression::Negative(negative_expression) => {
|
||||||
negative_expression.gather_declared_names(symbol_table)
|
negative_expression.type_check(symbol_table, types_table)
|
||||||
}
|
}
|
||||||
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
Expression::Call(call) => call.type_check(symbol_table, types_table),
|
||||||
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
Expression::Identifier(_) => Ok(()),
|
||||||
Expression::Integer(_) => Ok(()),
|
Expression::Integer(_) => Ok(()),
|
||||||
Expression::Double(_) => Ok(()),
|
Expression::Double(_) => Ok(()),
|
||||||
Expression::String(_) => Ok(()),
|
Expression::String(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_info<'a>(
|
||||||
match self {
|
&'a self,
|
||||||
Expression::Binary(binary_expression) => {
|
symbol_table: &SymbolTable,
|
||||||
binary_expression.check_name_usages(symbol_table)
|
types_table: &'a TypesTable,
|
||||||
}
|
) -> &'a TypeInfo {
|
||||||
Expression::Negative(negative_expression) => {
|
|
||||||
negative_expression.check_name_usages(symbol_table)
|
|
||||||
}
|
|
||||||
Expression::Call(call) => call.check_name_usages(symbol_table),
|
|
||||||
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
|
||||||
Expression::Integer(_) => Ok(()),
|
|
||||||
Expression::Double(_) => Ok(()),
|
|
||||||
Expression::String(_) => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
match self {
|
|
||||||
Expression::Binary(binary_expression) => binary_expression.type_check(symbol_table),
|
|
||||||
Expression::Negative(negative_expression) => {
|
|
||||||
negative_expression.type_check(symbol_table)
|
|
||||||
}
|
|
||||||
Expression::Call(call) => call.type_check(symbol_table),
|
|
||||||
Expression::Identifier(identifier) => identifier.type_check(symbol_table),
|
|
||||||
Expression::Integer(_) => Ok(()),
|
|
||||||
Expression::Double(_) => Ok(()),
|
|
||||||
Expression::String(_) => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
|
||||||
match self {
|
match self {
|
||||||
Expression::Binary(binary_expression) => binary_expression.type_info(),
|
Expression::Binary(binary_expression) => binary_expression.type_info(),
|
||||||
Expression::Negative(negative_expression) => negative_expression.type_info(),
|
Expression::Negative(negative_expression) => negative_expression.type_info(),
|
||||||
Expression::Call(call) => call.return_type_info(),
|
Expression::Call(call) => call.return_type_info(symbol_table, types_table),
|
||||||
Expression::Identifier(identifier) => identifier.type_info(),
|
Expression::Identifier(identifier) => identifier.type_info(symbol_table, types_table),
|
||||||
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
Expression::Integer(integer_literal) => integer_literal.type_info(),
|
||||||
Expression::Double(double_literal) => double_literal.type_info(),
|
Expression::Double(double_literal) => double_literal.type_info(),
|
||||||
Expression::String(string_literal) => string_literal.type_info(),
|
Expression::String(string_literal) => string_literal.type_info(),
|
||||||
@ -106,12 +211,15 @@ impl Expression {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> IrOperation {
|
) -> IrOperation {
|
||||||
match self {
|
match self {
|
||||||
Expression::Binary(binary_expression) => {
|
Expression::Binary(binary_expression) => {
|
||||||
binary_expression.to_ir_operation(builder, symbol_table)
|
binary_expression.to_ir_operation(builder, symbol_table, types_table)
|
||||||
|
}
|
||||||
|
Expression::Call(call) => {
|
||||||
|
IrOperation::Call(call.to_ir(builder, symbol_table, types_table))
|
||||||
}
|
}
|
||||||
Expression::Call(call) => IrOperation::Call(call.to_ir(builder, symbol_table)),
|
|
||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
IrOperation::Load(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
@ -122,10 +230,10 @@ impl Expression {
|
|||||||
IrOperation::Load(IrExpression::String(string_literal.content().into()))
|
IrOperation::Load(IrExpression::String(string_literal.content().into()))
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
Expression::Identifier(identifier) => {
|
||||||
IrOperation::Load(identifier.expressible_symbol().ir_expression(builder))
|
IrOperation::Load(identifier.ir_expression(builder, symbol_table))
|
||||||
}
|
}
|
||||||
Expression::Negative(negative_expression) => {
|
Expression::Negative(negative_expression) => {
|
||||||
IrOperation::Load(negative_expression.to_ir(builder, symbol_table))
|
IrOperation::Load(negative_expression.to_ir(builder, symbol_table, types_table))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,14 +242,21 @@ impl Expression {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> Option<IrExpression> {
|
) -> Option<IrExpression> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Binary(binary_expression) => {
|
Expression::Binary(binary_expression) => {
|
||||||
Some(binary_expression.to_ir_expression(builder, symbol_table))
|
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) => {
|
Expression::Call(call) => {
|
||||||
let ir_call = call.to_ir(builder, symbol_table);
|
let ir_call = call.to_ir(builder, symbol_table, types_table);
|
||||||
if matches!(call.return_type_info(), TypeInfo::Void) {
|
if matches!(
|
||||||
|
call.return_type_info(symbol_table, types_table),
|
||||||
|
TypeInfo::Void
|
||||||
|
) {
|
||||||
builder
|
builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
.add_statement(IrStatement::Call(ir_call));
|
.add_statement(IrStatement::Call(ir_call));
|
||||||
@ -150,7 +265,7 @@ impl Expression {
|
|||||||
let t_var = IrVariable::new_vr(
|
let t_var = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
call.return_type_info(),
|
call.return_type_info(symbol_table, types_table),
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(RefCell::new(t_var));
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
||||||
@ -160,6 +275,9 @@ impl Expression {
|
|||||||
Some(IrExpression::Variable(as_rc))
|
Some(IrExpression::Variable(as_rc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
Some(identifier.ir_expression(builder, symbol_table))
|
||||||
|
}
|
||||||
Expression::Integer(integer_literal) => {
|
Expression::Integer(integer_literal) => {
|
||||||
Some(IrExpression::Int(integer_literal.value()))
|
Some(IrExpression::Int(integer_literal.value()))
|
||||||
}
|
}
|
||||||
@ -169,13 +287,6 @@ impl Expression {
|
|||||||
Expression::String(string_literal) => {
|
Expression::String(string_literal) => {
|
||||||
Some(IrExpression::String(string_literal.content().into()))
|
Some(IrExpression::String(string_literal.content().into()))
|
||||||
}
|
}
|
||||||
Expression::Identifier(identifier) => {
|
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
|
||||||
Some(expressible_symbol.ir_expression(builder))
|
|
||||||
}
|
|
||||||
Expression::Negative(negative_expression) => {
|
|
||||||
Some(negative_expression.to_ir(builder, symbol_table))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,10 @@ use crate::ast::ir_builder::IrBuilder;
|
|||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_return::IrReturn;
|
use crate::ir::ir_return::IrReturn;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
pub struct ExpressionStatement {
|
pub struct ExpressionStatement {
|
||||||
expression: Box<Expression>,
|
expression: Box<Expression>,
|
||||||
@ -21,26 +23,42 @@ impl ExpressionStatement {
|
|||||||
&self.expression
|
&self.expression
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.expression.init_scopes(symbol_table, container_scope);
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
self.expression.gather_declared_names(symbol_table)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_constructor_local_names(
|
||||||
self.expression.check_name_usages(symbol_table)
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
class_symbol: &ClassSymbol,
|
||||||
|
) -> Vec<Diagnostic> {
|
||||||
|
self.expression
|
||||||
|
.check_constructor_local_names(symbol_table, class_symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
|
self.expression.check_static_fn_local_names(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(
|
pub fn type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
must_return_type_info: Option<&TypeInfo>,
|
must_return_type_info: Option<&TypeInfo>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.expression.type_check(symbol_table)?;
|
self.expression.type_check(symbol_table, types_table)?;
|
||||||
|
|
||||||
if must_return_type_info.is_some() {
|
if must_return_type_info.is_some() {
|
||||||
let expression_type = self.expression.type_info();
|
let expression_type = self.expression.type_info(symbol_table, types_table);
|
||||||
let return_type = must_return_type_info.unwrap();
|
let return_type = must_return_type_info.unwrap();
|
||||||
if !return_type.is_assignable_from(expression_type) {
|
if !return_type.is_assignable_from(expression_type) {
|
||||||
return Err(vec![Diagnostic::new(
|
return Err(vec![Diagnostic::new(
|
||||||
@ -60,9 +78,12 @@ impl ExpressionStatement {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
should_return_value: bool,
|
should_return_value: bool,
|
||||||
) {
|
) {
|
||||||
let ir_expression = self.expression.to_ir_expression(builder, symbol_table);
|
let ir_expression = self
|
||||||
|
.expression
|
||||||
|
.to_ir_expression(builder, symbol_table, types_table);
|
||||||
if ir_expression.is_some() && should_return_value {
|
if ir_expression.is_some() && should_return_value {
|
||||||
builder
|
builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::helpers::{collect_diagnostics_into_mut, gather_oks, map_symbol_insert_result};
|
use crate::ast::helpers::{collect_diagnostics_into_mut, collect_parameter_symbols_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::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics, ok_or_return};
|
use crate::{diagnostics_result, handle_diagnostics};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ExternFunction {
|
pub struct ExternFunction {
|
||||||
declared_name: String,
|
declared_name: Rc<str>,
|
||||||
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>,
|
||||||
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ impl ExternFunction {
|
|||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
|
scope_id: None,
|
||||||
function_symbol: None,
|
function_symbol: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,140 +41,46 @@ impl ExternFunction {
|
|||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts and saves a `FunctionSymbol`.
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
fn insert_save_function_symbol(
|
self.scope_id = Some(container_scope);
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table.push_function_scope(&format!("extern_function_scope({})", self.declared_name));
|
||||||
fqn_context: &FqnContext,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
for parameter in &mut self.parameters {
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
parameter.init_scopes(symbol_table, container_scope);
|
||||||
|
}
|
||||||
|
self.return_type.init_scopes(symbol_table, container_scope);
|
||||||
|
|
||||||
|
symbol_table.pop_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_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,
|
||||||
self.declared_name_source_range.clone(),
|
self.declared_name_source_range.clone(),
|
||||||
fqn_context.resolve(self.declared_name()),
|
fqn_context.resolve(self.declared_name()),
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
|
self.scope_id.unwrap(),
|
||||||
|
parameter_symbols,
|
||||||
));
|
));
|
||||||
|
all_symbols.push(Symbol::Function(function_symbol.clone()));
|
||||||
|
|
||||||
let function_symbol = ok_or_return!(map_symbol_insert_result(
|
(function_symbol, all_symbols)
|
||||||
insert_result,
|
|
||||||
&self.declared_name_source_range
|
|
||||||
));
|
|
||||||
|
|
||||||
self.function_symbol = Some(function_symbol);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gathers parameters' declared names, and sets `ParameterSymbols` on the `FunctionSymbol`.
|
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
fn gather_parameters_names(
|
let mut diagnostics: Vec<Diagnostic> = Vec::new();
|
||||||
&mut self,
|
for parameter in &self.parameters {
|
||||||
symbol_table: &mut SymbolTable,
|
diagnostics.append(&mut parameter.check_names(symbol_table));
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
}
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
diagnostics.append(&mut self.return_type.check_names(symbol_table));
|
||||||
|
diagnostics
|
||||||
let parameter_symbols = gather_oks(
|
|
||||||
&mut self.parameters,
|
|
||||||
|p| p.gather_declared_names(symbol_table),
|
|
||||||
&mut diagnostics,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Only continue if we have all the parameters and no diagnostics.
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
self.function_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_parameters(parameter_symbols);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers return type names
|
|
||||||
fn gather_return_type_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
handle_diagnostics!(
|
|
||||||
self.return_type.gather_declared_names(symbol_table),
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
self.insert_save_function_symbol(symbol_table, fqn_context)?;
|
|
||||||
|
|
||||||
symbol_table
|
|
||||||
.push_function_scope(&format!("extern_function_scope({})", &self.declared_name));
|
|
||||||
|
|
||||||
self.gather_parameters_names(symbol_table)
|
|
||||||
.inspect_err(|_| symbol_table.pop_scope())?; // pop scope if we had diagnostics!
|
|
||||||
|
|
||||||
// handle return type
|
|
||||||
self.gather_return_type_names(symbol_table)
|
|
||||||
.inspect_err(|_| symbol_table.pop_scope())?;
|
|
||||||
|
|
||||||
symbol_table.pop_scope(); // function scope
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_parameters_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
&mut self.parameters,
|
|
||||||
|p| p.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_return_type_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
handle_diagnostics!(
|
|
||||||
self.return_type
|
|
||||||
.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the `FunctionSymbol`'s return type info.
|
|
||||||
fn set_function_symbol_return_type(&mut self) {
|
|
||||||
self.function_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_return_type_info(self.return_type.type_info().clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_name_usages(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
self.check_parameters_names(symbol_table, class_context, &mut diagnostics);
|
|
||||||
|
|
||||||
self.check_return_type_names(symbol_table, class_context, &mut diagnostics);
|
|
||||||
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
// set return type info on symbol now that its available
|
|
||||||
self.set_function_symbol_return_type();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_check_parameters(
|
fn type_check_parameters(
|
||||||
|
|||||||
@ -4,7 +4,8 @@ use crate::diagnostic::Diagnostic;
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ 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>,
|
||||||
field_symbol: Option<Rc<RefCell<FieldSymbol>>>,
|
field_symbol: Option<Rc<RefCell<FieldSymbol>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ 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,
|
||||||
field_symbol: None,
|
field_symbol: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,77 +57,50 @@ impl Field {
|
|||||||
self.initializer.as_ref().map(Box::as_ref)
|
self.initializer.as_ref().map(Box::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.scope_id = Some(container_scope);
|
||||||
symbol_table: &mut SymbolTable,
|
if let Some(type_use) = &mut self.declared_type {
|
||||||
field_index: usize,
|
type_use.init_scopes(symbol_table, container_scope);
|
||||||
) -> Result<Rc<RefCell<FieldSymbol>>, Vec<Diagnostic>> {
|
}
|
||||||
// 1. insert field symbol
|
if let Some(expression) = &mut self.initializer {
|
||||||
let to_insert = FieldSymbol::new(
|
expression.init_scopes(symbol_table, container_scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_symbol(&self) -> FieldSymbol {
|
||||||
|
FieldSymbol::new(
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
self.declared_name_source_range.clone(),
|
self.declared_name_source_range.clone(),
|
||||||
self.is_mut,
|
self.is_mut,
|
||||||
);
|
self.scope_id.unwrap(),
|
||||||
|
)
|
||||||
let field_symbol = symbol_table
|
|
||||||
.insert_field_symbol(to_insert)
|
|
||||||
.map_err(|e| match e {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
vec![Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Symbol {} already declared in current scope.",
|
|
||||||
already_declared.symbol().borrow().declared_name()
|
|
||||||
),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// save for later
|
|
||||||
let to_return = field_symbol.clone();
|
|
||||||
self.field_symbol = Some(field_symbol);
|
|
||||||
|
|
||||||
// set field index on symbol
|
|
||||||
self.field_symbol
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_field_index(field_index);
|
|
||||||
|
|
||||||
// 2. gather type_use and initializer, if present
|
|
||||||
if let Some(type_use) = &mut self.declared_type {
|
|
||||||
type_use.gather_declared_names(symbol_table)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(initializer) = &mut self.initializer {
|
|
||||||
initializer.gather_declared_names(symbol_table)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
types_table: &TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
if let Some(type_use) = &mut self.declared_type {
|
|
||||||
type_use.check_name_usages(symbol_table, class_context)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is going to get hairy, because users might attempt to use a field in an initializer
|
|
||||||
// (for either this field, or another one) before it's actually initialized. As such, we
|
|
||||||
// need a way to prevent lookup of current class' fields in the initializer.
|
|
||||||
// For now, the following is okay so long as we don't start referencing things in the
|
|
||||||
// initializers.
|
|
||||||
if let Some(initializer) = self.initializer.as_mut() {
|
|
||||||
initializer.check_name_usages(symbol_table)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
if let Some(type_use) = &mut self.declared_type {
|
if let Some(type_use) = &mut self.declared_type {
|
||||||
@ -134,7 +110,9 @@ impl Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(initializer) = &mut self.initializer {
|
if let Some(initializer) = &mut self.initializer {
|
||||||
if let Some(mut initializer_diagnostics) = initializer.type_check(symbol_table).err() {
|
if let Some(mut initializer_diagnostics) =
|
||||||
|
initializer.type_check(symbol_table, types_table).err()
|
||||||
|
{
|
||||||
diagnostics.append(&mut initializer_diagnostics);
|
diagnostics.append(&mut initializer_diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +127,8 @@ impl Field {
|
|||||||
Some(type_use) => {
|
Some(type_use) => {
|
||||||
match self.initializer.as_ref() {
|
match self.initializer.as_ref() {
|
||||||
Some(initializer) => {
|
Some(initializer) => {
|
||||||
let initializer_type_info = initializer.type_info();
|
let initializer_type_info =
|
||||||
|
initializer.type_info(symbol_table, types_table);
|
||||||
let declared_type_info = type_use.type_info();
|
let declared_type_info = type_use.type_info();
|
||||||
if declared_type_info.is_assignable_from(initializer_type_info) {
|
if declared_type_info.is_assignable_from(initializer_type_info) {
|
||||||
declared_type_info
|
declared_type_info
|
||||||
@ -176,7 +155,7 @@ impl Field {
|
|||||||
None => {
|
None => {
|
||||||
// type is the initializer
|
// type is the initializer
|
||||||
match self.initializer.as_ref() {
|
match self.initializer.as_ref() {
|
||||||
Some(initializer) => initializer.type_info(),
|
Some(initializer) => initializer.type_info(symbol_table, types_table),
|
||||||
None => {
|
None => {
|
||||||
// this is an error
|
// this is an error
|
||||||
return Err(vec![Diagnostic::new(
|
return Err(vec![Diagnostic::new(
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::fqn_util::fqn_parts_to_string;
|
use crate::ast::fqn_util::fqn_parts_to_string;
|
||||||
use crate::ast::helpers::{
|
use crate::ast::helpers::{
|
||||||
collect_diagnostics_into_enumerated_mut, collect_diagnostics_into_mut, gather_oks,
|
collect_diagnostics_into_enumerated_mut, collect_diagnostics_into_mut,
|
||||||
map_symbol_insert_result,
|
collect_parameter_symbols_into,
|
||||||
};
|
};
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
@ -18,19 +18,19 @@ use crate::symbol::class_symbol::ClassSymbol;
|
|||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics, ok_or_return};
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use crate::{diagnostics_result, handle_diagnostics};
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
declared_name: String,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
is_public: bool,
|
is_public: bool,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
return_type: Option<TypeUse>,
|
return_type: Option<TypeUse>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
@ -43,13 +43,13 @@ impl Function {
|
|||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.to_string(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
is_public,
|
is_public,
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
statements,
|
statements,
|
||||||
function_symbol: None,
|
scope_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,220 +61,91 @@ impl Function {
|
|||||||
self.statements.iter().collect()
|
self.statements.iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a "self" parameter at index 0.
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
fn insert_self_parameter(&mut self) {
|
self.scope_id = Some(container_scope);
|
||||||
self.parameters.insert(
|
let function_scope =
|
||||||
0,
|
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
|
||||||
Parameter::new(
|
|
||||||
"self",
|
|
||||||
SourceRange::new(0, 0),
|
|
||||||
TypeUse::new("Self", SourceRange::new(0, 0), vec![]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `class_context` is `Some`, calls `insert_self_parameter()`.
|
for parameter in &mut self.parameters {
|
||||||
fn maybe_insert_self_parameter(&mut self, class_context: Option<&Rc<RefCell<ClassSymbol>>>) {
|
parameter.init_scopes(symbol_table, function_scope);
|
||||||
if class_context.is_some() {
|
|
||||||
self.insert_self_parameter();
|
|
||||||
}
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts and saves to self a `FunctionSymbol`
|
pub fn make_symbols(
|
||||||
fn insert_save_function_symbol(
|
&self,
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
fqn_context: &FqnContext,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
is_method: bool,
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
) -> (Rc<FunctionSymbol>, Vec<Symbol>) {
|
||||||
self.declared_name(),
|
let mut all_symbols: Vec<Symbol> = vec![];
|
||||||
|
|
||||||
|
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(),
|
self.declared_name_source_range.clone(),
|
||||||
fqn_context.resolve(self.declared_name()),
|
fqn_context.resolve(self.declared_name()),
|
||||||
false,
|
false,
|
||||||
|
is_method,
|
||||||
|
self.scope_id.unwrap(),
|
||||||
|
parameter_symbols,
|
||||||
));
|
));
|
||||||
|
all_symbols.push(Symbol::Function(function_symbol.clone()));
|
||||||
|
|
||||||
// get function symbol if successful
|
(function_symbol, all_symbols)
|
||||||
let function_symbol = ok_or_return!(map_symbol_insert_result(
|
|
||||||
insert_result,
|
|
||||||
&self.declared_name_source_range
|
|
||||||
));
|
|
||||||
|
|
||||||
// save function symbol for later
|
|
||||||
self.function_symbol = Some(function_symbol.clone());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gathers all declared names in parameters
|
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
fn gather_parameters_names(
|
let mut diagnostics = Vec::new();
|
||||||
&mut self,
|
for parameter in &self.parameters {
|
||||||
symbol_table: &mut SymbolTable,
|
diagnostics.append(&mut parameter.check_names(symbol_table));
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
// handle self case
|
|
||||||
self.maybe_insert_self_parameter(class_context);
|
|
||||||
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
// now gather all names for the params
|
|
||||||
let parameter_symbols = gather_oks(
|
|
||||||
&mut self.parameters,
|
|
||||||
|p| p.gather_declared_names(symbol_table),
|
|
||||||
&mut diagnostics,
|
|
||||||
);
|
|
||||||
|
|
||||||
// important: if there were diagnostics we don't have all the param symbols
|
|
||||||
// n.b.: passing pop_scope callback because we don't want to mess up the scopes for others
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
// set params on function symbol
|
|
||||||
self.function_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_parameters(parameter_symbols);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers all return type names
|
|
||||||
fn gather_return_type_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
self.return_type.as_mut_slice(),
|
|
||||||
|type_use| type_use.gather_declared_names(symbol_table),
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers all statements' names
|
|
||||||
fn gather_statements_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
&mut self.statements,
|
|
||||||
|s| s.gather_declared_names(symbol_table),
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
fqn_context: &FqnContext,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
// function symbol
|
|
||||||
self.insert_save_function_symbol(symbol_table, fqn_context)?;
|
|
||||||
|
|
||||||
// parameters
|
|
||||||
symbol_table.push_function_scope(&format!("function_scope({})", self.declared_name));
|
|
||||||
self.gather_parameters_names(symbol_table, class_context)
|
|
||||||
.inspect_err(|_| symbol_table.pop_scope())?; // if we errored, we need to fix scopes
|
|
||||||
|
|
||||||
// return type
|
|
||||||
let mut diagnostics = vec![];
|
|
||||||
self.gather_return_type_names(symbol_table, &mut diagnostics);
|
|
||||||
|
|
||||||
// enter main block
|
|
||||||
symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name));
|
|
||||||
|
|
||||||
// statements
|
|
||||||
self.gather_statements_names(symbol_table, &mut diagnostics);
|
|
||||||
|
|
||||||
symbol_table.pop_scope(); // main block scope
|
|
||||||
symbol_table.pop_scope(); // function scope
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks parameter name usages
|
|
||||||
fn check_parameter_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
collect_diagnostics_into_mut(
|
|
||||||
&mut self.parameters,
|
|
||||||
|p| p.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks return type name usages, if there is a `TypeUse` present. If `None`, sets the
|
|
||||||
/// `FunctionSymbol`'s return type to `TypeInfo::Void`.
|
|
||||||
fn check_return_type_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
|
||||||
) {
|
|
||||||
if let Some(type_use) = &mut self.return_type {
|
|
||||||
match type_use.check_name_usages(symbol_table, class_context) {
|
|
||||||
Ok(_) => {
|
|
||||||
// set return type info on function symbol
|
|
||||||
self.function_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_return_type_info(type_use.type_info().clone());
|
|
||||||
}
|
|
||||||
Err(mut type_use_diagnostics) => {
|
|
||||||
diagnostics.append(&mut type_use_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we don't have a given return type, so it's void
|
|
||||||
self.function_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_return_type_info(TypeInfo::Void);
|
|
||||||
}
|
}
|
||||||
|
if let Some(type_use) = &self.return_type {
|
||||||
|
diagnostics.append(&mut type_use.check_names(symbol_table));
|
||||||
|
}
|
||||||
|
diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks all statement name usages.
|
pub fn analyze_method_local_names(
|
||||||
fn check_statement_names(
|
&self,
|
||||||
&mut self,
|
symbol_table: &mut SymbolTable,
|
||||||
symbol_table: &SymbolTable,
|
class_symbol: &ClassSymbol,
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
) -> Vec<Diagnostic> {
|
||||||
) {
|
self.statements
|
||||||
collect_diagnostics_into_mut(
|
.iter()
|
||||||
&mut self.statements,
|
.flat_map(|statement| statement.analyze_method_local_names(symbol_table, class_symbol))
|
||||||
|s| s.check_name_usages(symbol_table),
|
.collect()
|
||||||
diagnostics,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn analyze_static_fn_local_names(&self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
&mut self,
|
self.statements
|
||||||
symbol_table: &SymbolTable,
|
.iter()
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
.flat_map(|statement| statement.analyze_static_fn_local_names(symbol_table))
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
.collect()
|
||||||
let mut diagnostics = vec![];
|
|
||||||
|
|
||||||
// parameters
|
|
||||||
self.check_parameter_names(symbol_table, class_context, &mut diagnostics);
|
|
||||||
|
|
||||||
// return type
|
|
||||||
self.check_return_type_names(symbol_table, class_context, &mut diagnostics);
|
|
||||||
|
|
||||||
// statements
|
|
||||||
self.check_statement_names(symbol_table, &mut diagnostics);
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the return type `TypeInfo`. This function is only safe to call after an `Ok` call to
|
fn get_return_type_info(
|
||||||
/// `check_return_type_names()`.
|
types_table: &TypesTable,
|
||||||
fn get_return_type_info(&self) -> TypeInfo {
|
function_symbol: &FunctionSymbol,
|
||||||
let function_symbol = self.function_symbol.as_ref().unwrap().borrow();
|
) -> TypeInfo {
|
||||||
function_symbol.return_type_info().clone()
|
types_table
|
||||||
|
.function_return_types()
|
||||||
|
.get(function_symbol)
|
||||||
|
.cloned()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type checks parameters.
|
/// Type checks parameters.
|
||||||
@ -305,9 +176,11 @@ impl Function {
|
|||||||
fn type_check_statements(
|
fn type_check_statements(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
diagnostics: &mut Vec<Diagnostic>,
|
diagnostics: &mut Vec<Diagnostic>,
|
||||||
|
function_symbol: &FunctionSymbol,
|
||||||
) {
|
) {
|
||||||
let return_type_info = self.get_return_type_info();
|
let return_type_info = Self::get_return_type_info(types_table, function_symbol);
|
||||||
let statements_len = self.statements.len();
|
let statements_len = self.statements.len();
|
||||||
|
|
||||||
collect_diagnostics_into_enumerated_mut(
|
collect_diagnostics_into_enumerated_mut(
|
||||||
@ -315,17 +188,24 @@ impl Function {
|
|||||||
|i, s| {
|
|i, s| {
|
||||||
let is_last = i == statements_len - 1;
|
let is_last = i == statements_len - 1;
|
||||||
if is_last {
|
if is_last {
|
||||||
s.type_check(symbol_table, Some(&return_type_info))
|
s.type_check(symbol_table, types_table, Some(&return_type_info))
|
||||||
} else {
|
} else {
|
||||||
s.type_check(symbol_table, None)
|
s.type_check(symbol_table, types_table, None)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
diagnostics,
|
diagnostics,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
let function_symbol = symbol_table
|
||||||
|
.get_function_symbol(self.scope_id.unwrap(), self.declared_name())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
self.type_check_parameters(symbol_table, &mut diagnostics);
|
self.type_check_parameters(symbol_table, &mut diagnostics);
|
||||||
@ -334,33 +214,39 @@ impl Function {
|
|||||||
self.type_check_return_type(symbol_table, &mut diagnostics);
|
self.type_check_return_type(symbol_table, &mut diagnostics);
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
self.type_check_statements(symbol_table, &mut diagnostics);
|
self.type_check_statements(symbol_table, types_table, &mut diagnostics, function_symbol);
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
diagnostics_result!(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts all parameters to ir. Saves the IrParameter to the associated parameter symbol.
|
/// Converts all parameters to ir. Saves the IrParameter to the associated parameter symbol.
|
||||||
fn parameters_to_ir(&self, builder: &mut IrBuilder) {
|
fn parameters_to_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) {
|
||||||
for (i, parameter) in self.parameters.iter().enumerate() {
|
for (i, parameter) in self.parameters.iter().enumerate() {
|
||||||
let parameter_symbol = parameter.parameter_symbol();
|
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(¶meter_symbol)
|
||||||
|
.unwrap();
|
||||||
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
|
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
|
||||||
let ir_parameter = IrParameter::new(
|
let ir_parameter = IrParameter::new(
|
||||||
parameter_symbol.borrow().declared_name(),
|
parameter_symbol.declared_name(),
|
||||||
parameter_symbol.borrow().type_info().clone(),
|
parameter_type_info.clone(),
|
||||||
stack_offset,
|
stack_offset,
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(ir_parameter);
|
let as_rc = Rc::new(ir_parameter);
|
||||||
builder.parameters_mut().push(as_rc.clone());
|
builder.push_parameter(¶meter_symbol, as_rc.clone());
|
||||||
parameter_symbol.borrow_mut().set_ir_parameter(as_rc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `class_context.is_some()`, set parameter 0 to the self parameter/variable on the builder.
|
/// If `class_context.is_some()`, set parameter 0 to the self parameter/variable on the builder.
|
||||||
fn handle_method_case(
|
fn handle_method_case(&self, builder: &mut IrBuilder, class_context: Option<&ClassSymbol>) {
|
||||||
&self,
|
|
||||||
builder: &mut IrBuilder,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) {
|
|
||||||
// if we are a method, we need to set the self parameter on the builder
|
// if we are a method, we need to set the self parameter on the builder
|
||||||
if class_context.is_some() {
|
if class_context.is_some() {
|
||||||
let parameter_0 = builder.parameters()[0].clone();
|
let parameter_0 = builder.parameters()[0].clone();
|
||||||
@ -370,24 +256,39 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert all statements to ir.
|
/// Convert all statements to ir.
|
||||||
fn statements_to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
fn statements_to_ir(
|
||||||
let return_type_info = self.get_return_type_info();
|
&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);
|
let should_return_value = !matches!(return_type_info, TypeInfo::Void);
|
||||||
for (i, statement) in self.statements.iter().enumerate() {
|
for (i, statement) in self.statements.iter().enumerate() {
|
||||||
let is_last = i == self.statements.len() - 1;
|
let is_last = i == self.statements.len() - 1;
|
||||||
statement.to_ir(builder, symbol_table, should_return_value && is_last);
|
statement.to_ir(
|
||||||
|
builder,
|
||||||
|
symbol_table,
|
||||||
|
types_table,
|
||||||
|
should_return_value && is_last,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(
|
pub fn to_ir(
|
||||||
&self,
|
&self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
types_table: &TypesTable,
|
||||||
|
class_context: Option<&ClassSymbol>,
|
||||||
) -> IrFunction {
|
) -> IrFunction {
|
||||||
let mut builder = IrBuilder::new();
|
let mut builder = IrBuilder::new();
|
||||||
|
let function_symbol = symbol_table
|
||||||
|
.get_function_symbol(self.scope_id.unwrap(), self.declared_name())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
self.parameters_to_ir(&mut builder);
|
self.parameters_to_ir(&mut builder, symbol_table, types_table);
|
||||||
|
|
||||||
let entry_block_id = builder.new_block();
|
let entry_block_id = builder.new_block();
|
||||||
|
|
||||||
@ -395,15 +296,15 @@ impl Function {
|
|||||||
self.handle_method_case(&mut builder, class_context);
|
self.handle_method_case(&mut builder, class_context);
|
||||||
|
|
||||||
// body
|
// body
|
||||||
self.statements_to_ir(&mut builder, symbol_table);
|
self.statements_to_ir(&mut builder, symbol_table, types_table, function_symbol);
|
||||||
|
|
||||||
builder.finish_block();
|
builder.finish_block();
|
||||||
|
|
||||||
let entry_block = builder.get_block(entry_block_id).clone();
|
let entry_block = builder.get_block(entry_block_id).clone();
|
||||||
IrFunction::new(
|
IrFunction::new(
|
||||||
fqn_parts_to_string(self.function_symbol.as_ref().unwrap().borrow().fqn_parts()),
|
fqn_parts_to_string(function_symbol.fqn_parts()),
|
||||||
builder.parameters(),
|
builder.parameters().iter().map(|p| (*p).clone()).collect(),
|
||||||
&self.get_return_type_info(),
|
&Self::get_return_type_info(types_table, function_symbol),
|
||||||
entry_block,
|
entry_block,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::error_codes::SYMBOL_ALREADY_DECLARED;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics};
|
use crate::{diagnostics_result, handle_diagnostics};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -13,6 +11,7 @@ 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>>>,
|
generic_parameter_symbol: Option<Rc<RefCell<GenericParameterSymbol>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,87 +25,31 @@ 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,
|
generic_parameter_symbol: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.scope_id = Some(container_scope);
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<Rc<RefCell<GenericParameterSymbol>>, Vec<Diagnostic>> {
|
|
||||||
// insert symbol
|
|
||||||
let to_insert =
|
|
||||||
GenericParameterSymbol::new(&self.declared_name, &self.declared_name_source_range);
|
|
||||||
let to_return = match symbol_table.insert_generic_parameter_symbol(to_insert) {
|
|
||||||
Ok(generic_parameter_symbol) => generic_parameter_symbol,
|
|
||||||
Err(symbol_insert_error) => {
|
|
||||||
return match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
let already_declared_symbol = already_declared.symbol().borrow();
|
|
||||||
let already_declared_source_range =
|
|
||||||
already_declared_symbol.declared_name_source_range();
|
|
||||||
let diagnostic = Diagnostic::new(
|
|
||||||
&format!("Symbol {} already declared in scope.", self.declared_name),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!())
|
|
||||||
.with_error_code(SYMBOL_ALREADY_DECLARED)
|
|
||||||
.with_secondary_labels(&[SecondaryLabel::new(
|
|
||||||
already_declared_source_range.start(),
|
|
||||||
already_declared_source_range.end(),
|
|
||||||
Some("Symbol already declared here.".to_string()),
|
|
||||||
)]);
|
|
||||||
Err(vec![diagnostic])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// save param symbol
|
|
||||||
self.generic_parameter_symbol = Some(to_return.clone());
|
|
||||||
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
for type_use in &mut self.extends {
|
for type_use in &mut self.extends {
|
||||||
handle_diagnostics!(type_use.gather_declared_names(symbol_table), diagnostics);
|
type_use.init_scopes(symbol_table, container_scope);
|
||||||
}
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(to_return)
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn make_symbol(&self) -> GenericParameterSymbol {
|
||||||
&mut self,
|
GenericParameterSymbol::new(
|
||||||
symbol_table: &SymbolTable,
|
&self.declared_name,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
&self.declared_name_source_range,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
self.scope_id.unwrap(),
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
)
|
||||||
// check the extends type uses
|
}
|
||||||
for type_use in &mut self.extends {
|
|
||||||
handle_diagnostics!(
|
|
||||||
type_use.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
// now that each extends type use has type info, set the type infos on the generic parameter
|
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
let extends_type_infos = self
|
self.extends
|
||||||
.extends
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|type_use| type_use.type_info().clone())
|
.flat_map(|type_use| type_use.check_names(symbol_table))
|
||||||
.collect::<Vec<_>>();
|
.collect()
|
||||||
self.generic_parameter_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_extends(extends_type_infos);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
|
use crate::ast::diagnostic_factories::symbol_already_declared;
|
||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
use crate::ast::parameter::Parameter;
|
||||||
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::diagnostics_result;
|
use crate::diagnostics_result;
|
||||||
use crate::error_codes::SYMBOL_ALREADY_DECLARED;
|
use crate::symbol::Symbol;
|
||||||
use crate::source_range::SourceRange;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::symbol_table::SymbolInsertError;
|
use crate::symbol_table::SymbolTable;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Iterates through all `ts`, running the `f` function, and pushing returned `Diagnostic`s
|
/// Iterates through all `ts`, running the `f` function, and pushing returned `Diagnostic`s
|
||||||
@ -72,36 +74,6 @@ pub fn collect_diagnostics_single<T>(
|
|||||||
diagnostics_result!(diagnostics)
|
diagnostics_result!(diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_symbol_insert_result<T>(
|
|
||||||
insert_result: Result<T, SymbolInsertError>,
|
|
||||||
declared_name_source_range: &SourceRange,
|
|
||||||
) -> Result<T, Vec<Diagnostic>> {
|
|
||||||
match insert_result {
|
|
||||||
Ok(symbol) => Ok(symbol),
|
|
||||||
Err(symbol_insert_error) => match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
let already_declared_symbol = already_declared.symbol().borrow();
|
|
||||||
let diagnostic = Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Symbol {} already declared in current scope.",
|
|
||||||
already_declared_symbol.declared_name()
|
|
||||||
),
|
|
||||||
declared_name_source_range.start(),
|
|
||||||
declared_name_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!())
|
|
||||||
.with_error_code(SYMBOL_ALREADY_DECLARED)
|
|
||||||
.with_secondary_labels(&[SecondaryLabel::new(
|
|
||||||
already_declared_symbol.declared_name_source_range().start(),
|
|
||||||
already_declared_symbol.declared_name_source_range().end(),
|
|
||||||
Some("Symbol already declared here.".to_string()),
|
|
||||||
)]);
|
|
||||||
Err(vec![diagnostic])
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_oks<T, R>(
|
pub fn gather_oks<T, R>(
|
||||||
ts: &mut [T],
|
ts: &mut [T],
|
||||||
mut f: impl FnMut(&mut T) -> Result<R, Vec<Diagnostic>>,
|
mut f: impl FnMut(&mut T) -> Result<R, Vec<Diagnostic>>,
|
||||||
@ -122,3 +94,40 @@ pub fn gather_oks<T, R>(
|
|||||||
pub fn resolve_ctor_name(fqn_context: &FqnContext) -> Vec<Rc<str>> {
|
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
|
fqn_context.resolve("ctor") // ctor is a keyword at the language level, should not be callable via normal means
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_insert_symbol_into(
|
||||||
|
symbol: Symbol,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Diagnostic> {
|
||||||
|
let maybe_already_inserted = symbol_table.get_symbol(symbol.scope_id(), symbol.declared_name());
|
||||||
|
if let Some(already_inserted) = maybe_already_inserted {
|
||||||
|
Err(symbol_already_declared(&already_inserted, &symbol))
|
||||||
|
} else {
|
||||||
|
symbol_table.insert_symbol(symbol);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_insert_symbols_into(
|
||||||
|
symbols: Vec<Symbol>,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let diagnostics: Vec<Diagnostic> = symbols
|
||||||
|
.into_iter()
|
||||||
|
.map(|symbol| try_insert_symbol_into(symbol, symbol_table))
|
||||||
|
.filter_map(Result::err)
|
||||||
|
.collect();
|
||||||
|
diagnostics_result!(diagnostics)
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,25 +1,39 @@
|
|||||||
|
use crate::ast::diagnostic_factories::{
|
||||||
|
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::ast::ir_builder::IrBuilder;
|
||||||
|
use crate::ast::ir_util::get_or_init_field_pointer_variable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::ir::ir_assign::IrAssign;
|
||||||
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_operation::IrOperation;
|
||||||
|
use crate::ir::ir_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::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
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::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Identifier {
|
pub struct Identifier {
|
||||||
name: String,
|
name: String,
|
||||||
scope_id: Option<usize>,
|
|
||||||
expressible_symbol: Option<ExpressibleSymbol>,
|
|
||||||
type_info: Option<TypeInfo>,
|
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identifier {
|
impl Identifier {
|
||||||
pub fn new(name: &str, source_range: SourceRange) -> Self {
|
pub fn new(name: &str, source_range: SourceRange) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
scope_id: None,
|
|
||||||
expressible_symbol: None,
|
|
||||||
type_info: None,
|
|
||||||
source_range,
|
source_range,
|
||||||
|
scope_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,45 +41,237 @@ impl Identifier {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scope_id(&mut self, container_scope: usize) {
|
||||||
&mut self,
|
self.scope_id = Some(container_scope);
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
self.scope_id = Some(symbol_table.current_scope_id());
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn scope_id(&self) -> usize {
|
||||||
let maybe_expressible_symbol =
|
self.scope_id.unwrap()
|
||||||
symbol_table.find_expressible_symbol(self.scope_id.unwrap(), &self.name);
|
}
|
||||||
match maybe_expressible_symbol {
|
|
||||||
None => Err(vec![Diagnostic::new(
|
/// Check against recursively constructing this class.
|
||||||
&format!("Unable to resolve symbol {}", self.name),
|
fn check_self_constructor_use(
|
||||||
self.source_range.start(),
|
&self,
|
||||||
self.source_range.end(),
|
context_class_symbol: &ClassSymbol,
|
||||||
)]),
|
class_symbol: &ClassSymbol,
|
||||||
Some(expressible_symbol) => {
|
) -> Option<Diagnostic> {
|
||||||
self.expressible_symbol = Some(expressible_symbol);
|
// this is not future-proof, as we will eventually allow reference to the self class, which
|
||||||
Ok(())
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
/// Check against using this or outer class' bare fields.
|
||||||
let type_info = self.expressible_symbol.as_ref().unwrap().type_info();
|
fn check_self_or_outer_field_use(
|
||||||
self.type_info = Some(type_info);
|
&self,
|
||||||
Ok(())
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
/// Check against using self or outer class methods.
|
||||||
self.type_info.as_ref().unwrap()
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expressible_symbol(&self) -> &ExpressibleSymbol {
|
pub fn check_name_as_field_initializer(
|
||||||
self.expressible_symbol.as_ref().unwrap()
|
&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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
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 type_info<'a>(
|
||||||
|
&self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &'a TypesTable,
|
||||||
|
) -> &'a TypeInfo {
|
||||||
|
let variable_symbol = symbol_table
|
||||||
|
.get_variable_symbol(self.scope_id.unwrap(), &self.name)
|
||||||
|
.unwrap();
|
||||||
|
types_table.variable_types().get(variable_symbol).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ir_expression(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> 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 read_destination = IrVariable::new_vr(
|
||||||
|
builder.new_t_var().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
field_symbol.type_info(),
|
||||||
|
);
|
||||||
|
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
|
||||||
|
let ir_read_field = IrReadField::new(
|
||||||
|
get_or_init_field_pointer_variable(builder, &field_symbol).clone(),
|
||||||
|
);
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(IrAssign::new(
|
||||||
|
read_destination_as_rc.clone(),
|
||||||
|
IrOperation::ReadField(ir_read_field),
|
||||||
|
)));
|
||||||
|
IrExpression::Variable(read_destination_as_rc)
|
||||||
|
}
|
||||||
|
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(¶meter_symbol).unwrap();
|
||||||
|
IrExpression::Parameter(ir_parameter.clone())
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||||
|
let ir_variable = builder.local_variables().get(&variable_symbol).unwrap();
|
||||||
|
IrExpression::Variable(ir_variable.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,15 @@ use crate::ir::ir_parameter::IrParameter;
|
|||||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
use crate::ir::ir_variable::IrVariable;
|
||||||
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct IrBuilder {
|
pub struct IrBuilder {
|
||||||
parameters: Vec<Rc<IrParameter>>,
|
parameters: Vec<(Rc<ParameterSymbol>, Rc<IrParameter>)>,
|
||||||
|
local_variables: HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>>,
|
||||||
block_counter: usize,
|
block_counter: usize,
|
||||||
t_var_counter: usize,
|
t_var_counter: usize,
|
||||||
blocks: HashMap<usize, Rc<RefCell<IrBlock>>>,
|
blocks: HashMap<usize, Rc<RefCell<IrBlock>>>,
|
||||||
@ -22,6 +25,7 @@ impl IrBuilder {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
parameters: vec![],
|
parameters: vec![],
|
||||||
|
local_variables: HashMap::new(),
|
||||||
block_counter: 0,
|
block_counter: 0,
|
||||||
t_var_counter: 0,
|
t_var_counter: 0,
|
||||||
blocks: HashMap::new(),
|
blocks: HashMap::new(),
|
||||||
@ -32,12 +36,37 @@ impl IrBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameters(&self) -> &[Rc<IrParameter>] {
|
pub fn local_variables(&self) -> &HashMap<Rc<VariableSymbol>, Rc<RefCell<IrVariable>>> {
|
||||||
&self.parameters
|
&self.local_variables
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameters_mut(&mut self) -> &mut Vec<Rc<IrParameter>> {
|
pub fn local_variables_mut(
|
||||||
&mut self.parameters
|
&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 {
|
pub fn new_block(&mut self) -> usize {
|
||||||
|
|||||||
@ -5,25 +5,24 @@ use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
|
|||||||
use crate::ir::ir_operation::IrOperation;
|
use crate::ir::ir_operation::IrOperation;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
use crate::ir::ir_variable::IrVariable;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub fn get_or_init_field_pointer_variable<'a>(
|
pub fn get_or_init_field_pointer_variable<'a>(
|
||||||
builder: &'a mut IrBuilder,
|
builder: &'a mut IrBuilder,
|
||||||
field_symbol: &Rc<RefCell<FieldSymbol>>,
|
field_symbol: &Rc<FieldSymbol>,
|
||||||
) -> &'a Rc<RefCell<IrVariable>> {
|
) -> &'a Rc<RefCell<IrVariable>> {
|
||||||
// This following should work because blocks are flat in the ir; if a variable is defined in the
|
// 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.
|
// ir block from this point forward, it's available to all subsequent blocks.
|
||||||
if !builder
|
if !builder
|
||||||
.field_pointer_variables()
|
.field_pointer_variables()
|
||||||
.contains_key(field_symbol.borrow().declared_name())
|
.contains_key(field_symbol.declared_name())
|
||||||
{
|
{
|
||||||
let field_ref_variable = IrVariable::new_vr(
|
let field_ref_variable = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
field_symbol.borrow().type_info(),
|
field_symbol.type_info(),
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(RefCell::new(field_ref_variable));
|
let as_rc = Rc::new(RefCell::new(field_ref_variable));
|
||||||
let to_insert = as_rc.clone();
|
let to_insert = as_rc.clone();
|
||||||
@ -34,31 +33,31 @@ pub fn get_or_init_field_pointer_variable<'a>(
|
|||||||
as_rc,
|
as_rc,
|
||||||
IrOperation::GetFieldRef(IrGetFieldRef::new(
|
IrOperation::GetFieldRef(IrGetFieldRef::new(
|
||||||
self_parameter_or_variable.clone(),
|
self_parameter_or_variable.clone(),
|
||||||
field_symbol.borrow().field_index(),
|
field_symbol.field_index(),
|
||||||
)),
|
)),
|
||||||
)));
|
)));
|
||||||
builder
|
builder
|
||||||
.field_pointer_variables_mut()
|
.field_pointer_variables_mut()
|
||||||
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
|
.insert(field_symbol.declared_name_owned(), to_insert);
|
||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.field_pointer_variables()
|
.field_pointer_variables()
|
||||||
.get(field_symbol.borrow().declared_name())
|
.get(field_symbol.declared_name())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_init_mut_field_pointer_variable<'a>(
|
pub fn get_or_init_mut_field_pointer_variable<'a>(
|
||||||
builder: &'a mut IrBuilder,
|
builder: &'a mut IrBuilder,
|
||||||
field_symbol: &Rc<RefCell<FieldSymbol>>,
|
field_symbol: &Rc<FieldSymbol>,
|
||||||
) -> &'a Rc<RefCell<IrVariable>> {
|
) -> &'a Rc<RefCell<IrVariable>> {
|
||||||
if !builder
|
if !builder
|
||||||
.field_mut_pointer_variables()
|
.field_mut_pointer_variables()
|
||||||
.contains_key(field_symbol.borrow().declared_name())
|
.contains_key(field_symbol.declared_name())
|
||||||
{
|
{
|
||||||
let mut_field_pointer_variable = IrVariable::new_vr(
|
let mut_field_pointer_variable = IrVariable::new_vr(
|
||||||
builder.new_t_var().into(),
|
builder.new_t_var().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
field_symbol.borrow().type_info(),
|
field_symbol.type_info(),
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(RefCell::new(mut_field_pointer_variable));
|
let as_rc = Rc::new(RefCell::new(mut_field_pointer_variable));
|
||||||
let to_insert = as_rc.clone();
|
let to_insert = as_rc.clone();
|
||||||
@ -69,15 +68,15 @@ pub fn get_or_init_mut_field_pointer_variable<'a>(
|
|||||||
as_rc,
|
as_rc,
|
||||||
IrOperation::GetFieldRefMut(IrGetFieldRefMut::new(
|
IrOperation::GetFieldRefMut(IrGetFieldRefMut::new(
|
||||||
self_parameter_or_variable.clone(),
|
self_parameter_or_variable.clone(),
|
||||||
field_symbol.borrow().field_index(),
|
field_symbol.field_index(),
|
||||||
)),
|
)),
|
||||||
)));
|
)));
|
||||||
builder
|
builder
|
||||||
.field_mut_pointer_variables_mut()
|
.field_mut_pointer_variables_mut()
|
||||||
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
|
.insert(field_symbol.declared_name_owned(), to_insert);
|
||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.field_mut_pointer_variables()
|
.field_mut_pointer_variables()
|
||||||
.get(field_symbol.borrow().declared_name())
|
.get(field_symbol.declared_name())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::ast::helpers::try_insert_symbol_into;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_assign::IrAssign;
|
use crate::ir::ir_assign::IrAssign;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
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::variable_symbol::VariableSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -46,76 +50,125 @@ impl LetStatement {
|
|||||||
&mut self.initializer
|
&mut self.initializer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
self.scope_id = Some(container_scope);
|
||||||
|
self.initializer.init_scopes(symbol_table, container_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_and_insert_variable_symbol(
|
||||||
|
&self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Option<Diagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let variable_symbol = Rc::new(VariableSymbol::new(
|
||||||
|
|
||||||
match self.initializer_mut().gather_declared_names(symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut initializer_diagnostics) => {
|
|
||||||
diagnostics.append(&mut initializer_diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
|
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
self.declared_name_source_range.clone(),
|
&self.declared_name_source_range,
|
||||||
self.is_mut,
|
self.is_mut,
|
||||||
|
self.scope_id.unwrap(),
|
||||||
));
|
));
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
try_insert_symbol_into(Symbol::Variable(variable_symbol), symbol_table).err()
|
||||||
match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
diagnostics.push(Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Symbol {} already declared in current scope",
|
|
||||||
already_declared.symbol().borrow().declared_name()
|
|
||||||
),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.scope_id = Some(symbol_table.current_scope_id());
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn analyze_constructor_local_names(
|
||||||
self.initializer.check_name_usages(symbol_table)
|
&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
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn analyze_method_local_names(
|
||||||
self.initializer.type_check(symbol_table)?;
|
&self,
|
||||||
let initializer_type_info = self.initializer.type_info();
|
symbol_table: &mut SymbolTable,
|
||||||
let variable_symbol =
|
class_symbol: &ClassSymbol,
|
||||||
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
) -> Vec<Diagnostic> {
|
||||||
variable_symbol
|
let mut diagnostics = Vec::new();
|
||||||
.borrow_mut()
|
diagnostics.append(
|
||||||
.set_type_info(initializer_type_info.clone());
|
&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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 type_check(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.initializer.type_check(symbol_table, types_table)?;
|
||||||
|
let initializer_type_info = self.initializer.type_info(symbol_table, types_table);
|
||||||
|
let variable_symbol = symbol_table
|
||||||
|
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
|
||||||
|
.unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) {
|
pub fn to_ir(
|
||||||
let init_operation = self.initializer.to_ir_operation(builder, symbol_table);
|
&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 = symbol_table
|
||||||
|
.get_variable_symbol_owned(self.scope_id.unwrap(), &self.declared_name)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let destination_type = types_table
|
||||||
|
.variable_types()
|
||||||
|
.get(&destination_symbol)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let destination_symbol =
|
|
||||||
symbol_table.get_variable_symbol(self.scope_id.unwrap(), &self.declared_name);
|
|
||||||
let destination_vr_variable = IrVariable::new_vr(
|
let destination_vr_variable = IrVariable::new_vr(
|
||||||
self.declared_name().into(),
|
self.declared_name().into(),
|
||||||
builder.current_block().id(),
|
builder.current_block().id(),
|
||||||
self.initializer.type_info(),
|
destination_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
|
let as_rc = Rc::new(RefCell::new(destination_vr_variable));
|
||||||
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
|
let ir_assign = IrAssign::new(as_rc.clone(), init_operation);
|
||||||
destination_symbol.borrow_mut().set_vr_variable(as_rc);
|
|
||||||
|
builder
|
||||||
|
.local_variables_mut()
|
||||||
|
.insert(destination_symbol, as_rc.clone());
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
|
|||||||
@ -4,6 +4,7 @@ pub mod call;
|
|||||||
pub mod class;
|
pub mod class;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
pub mod constructor;
|
pub mod constructor;
|
||||||
|
mod diagnostic_factories;
|
||||||
pub mod double_literal;
|
pub mod double_literal;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub mod expression_statement;
|
pub mod expression_statement;
|
||||||
|
|||||||
@ -8,8 +8,10 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
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::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -40,21 +42,49 @@ impl NegativeExpression {
|
|||||||
&mut self.operand
|
&mut self.operand
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
|
self.operand.init_scopes(symbol_table, container_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_static_fn_local_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
|
self.operand.check_static_fn_local_names(symbol_table)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.operand.gather_declared_names(symbol_table)
|
self.operand.type_check(symbol_table, types_table)?;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
let type_info = self.operand.type_info(symbol_table, types_table);
|
||||||
self.operand.check_name_usages(symbol_table)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
self.operand.type_check(symbol_table)?;
|
|
||||||
|
|
||||||
let type_info = self.operand.type_info();
|
|
||||||
if type_info.can_negate() {
|
if type_info.can_negate() {
|
||||||
self.type_info = Some(type_info.negate_result());
|
self.type_info = Some(type_info.negate_result());
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -67,10 +97,15 @@ impl NegativeExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrExpression {
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
|
) -> IrExpression {
|
||||||
let operand_as_ir = self
|
let operand_as_ir = self
|
||||||
.operand
|
.operand
|
||||||
.to_ir_expression(builder, symbol_table)
|
.to_ir_expression(builder, symbol_table, types_table)
|
||||||
.expect("Attempt to negate non-value expression");
|
.expect("Attempt to negate non-value expression");
|
||||||
|
|
||||||
match operand_as_ir {
|
match operand_as_ir {
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::SymbolTable;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Parameter {
|
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,
|
||||||
parameter_symbol: Option<Rc<RefCell<ParameterSymbol>>>,
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parameter {
|
impl Parameter {
|
||||||
@ -24,71 +22,37 @@ impl Parameter {
|
|||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
type_use,
|
type_use,
|
||||||
parameter_symbol: None,
|
scope_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn declared_name(&self) -> &str {
|
||||||
&mut self,
|
&self.declared_name
|
||||||
symbol_table: &mut SymbolTable,
|
}
|
||||||
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
|
|
||||||
// insert parameter symbol
|
pub fn scope_id(&self) -> usize {
|
||||||
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
|
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,
|
&self.declared_name,
|
||||||
self.declared_name_source_range.clone(),
|
self.declared_name_source_range.clone(),
|
||||||
));
|
self.scope_id.unwrap(),
|
||||||
match insert_result {
|
)
|
||||||
Ok(parameter_symbol) => {
|
|
||||||
self.parameter_symbol = Some(parameter_symbol.clone());
|
|
||||||
}
|
|
||||||
Err(symbol_insert_error) => {
|
|
||||||
return match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
Err(vec![Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Parameter {} already declared.",
|
|
||||||
already_declared.symbol().borrow().declared_name()
|
|
||||||
),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// type use
|
|
||||||
self.type_use.gather_declared_names(symbol_table)?;
|
|
||||||
|
|
||||||
Ok(self.parameter_symbol.clone().unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn check_names(&self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
&mut self,
|
self.type_use.check_names(symbol_table)
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
// check the type use
|
|
||||||
self.type_use
|
|
||||||
.check_name_usages(symbol_table, class_context)?;
|
|
||||||
|
|
||||||
// set type on parameter symbol
|
|
||||||
self.parameter_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_type_info(self.type_use.type_info().clone());
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.type_use.type_check(symbol_table)?;
|
self.type_use.type_check(symbol_table)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameter_symbol(&self) -> &Rc<RefCell<ParameterSymbol>> {
|
|
||||||
self.parameter_symbol
|
|
||||||
.as_ref()
|
|
||||||
.expect("parameter symbol not initialized")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,10 @@ use crate::ast::expression_statement::ExpressionStatement;
|
|||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
@ -13,42 +15,84 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn gather_declared_names(
|
pub fn init_scopes(&mut self, symbol_table: &mut SymbolTable, container_scope: usize) {
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.gather_declared_names(symbol_table),
|
Statement::Let(let_statement) => {
|
||||||
|
let_statement.init_scopes(symbol_table, container_scope);
|
||||||
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.gather_declared_names(symbol_table)
|
expression_statement.init_scopes(symbol_table, container_scope);
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => {
|
Statement::Assign(assign_statement) => {
|
||||||
assign_statement.gather_declared_names(symbol_table)
|
assign_statement.init_scopes(symbol_table, container_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn analyze_constructor_local_names(
|
||||||
|
&self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
class_symbol: &ClassSymbol,
|
||||||
|
) -> Vec<Diagnostic> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.check_name_usages(symbol_table),
|
Statement::Let(let_statement) => {
|
||||||
Statement::Expression(expression_statement) => {
|
let_statement.analyze_constructor_local_names(symbol_table, class_symbol)
|
||||||
expression_statement.check_name_usages(symbol_table)
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => assign_statement.check_name_usages(symbol_table),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(
|
pub fn type_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &mut TypesTable,
|
||||||
must_return_type_info: Option<&TypeInfo>,
|
must_return_type_info: Option<&TypeInfo>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => let_statement.type_check(symbol_table),
|
Statement::Let(let_statement) => let_statement.type_check(symbol_table, types_table),
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.type_check(symbol_table, must_return_type_info)
|
expression_statement.type_check(symbol_table, types_table, must_return_type_info)
|
||||||
|
}
|
||||||
|
Statement::Assign(assign_statement) => {
|
||||||
|
assign_statement.type_check(symbol_table, types_table)
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => assign_statement.type_check(symbol_table),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,17 +100,18 @@ impl Statement {
|
|||||||
&self,
|
&self,
|
||||||
builder: &mut IrBuilder,
|
builder: &mut IrBuilder,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
|
types_table: &TypesTable,
|
||||||
should_return_value: bool,
|
should_return_value: bool,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => {
|
Statement::Let(let_statement) => {
|
||||||
let_statement.to_ir(builder, symbol_table);
|
let_statement.to_ir(builder, symbol_table, types_table);
|
||||||
}
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.to_ir(builder, symbol_table, should_return_value);
|
expression_statement.to_ir(builder, symbol_table, types_table, should_return_value);
|
||||||
}
|
}
|
||||||
Statement::Assign(assign_statement) => {
|
Statement::Assign(assign_statement) => {
|
||||||
assign_statement.to_ir(builder, symbol_table);
|
assign_statement.to_ir(builder, symbol_table, types_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::ast::diagnostic_factories::symbol_not_found;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS;
|
use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
@ -9,7 +10,7 @@ use std::cell::RefCell;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct TypeUse {
|
pub struct TypeUse {
|
||||||
declared_name: String,
|
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>,
|
scope_id: Option<usize>,
|
||||||
@ -35,6 +36,34 @@ impl TypeUse {
|
|||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 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 {
|
||||||
|
type_use.check_names(symbol_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn gather_declared_names(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
@ -53,7 +82,7 @@ impl TypeUse {
|
|||||||
pub fn check_name_usages(
|
pub fn check_name_usages(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
class_context: Option<&Rc<ClassSymbol>>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
@ -90,8 +119,7 @@ impl TypeUse {
|
|||||||
match self.type_info() {
|
match self.type_info() {
|
||||||
TypeInfo::ClassInstance(class_symbol) => {
|
TypeInfo::ClassInstance(class_symbol) => {
|
||||||
// check number of params/args match
|
// check number of params/args match
|
||||||
let borrowed_class_symbol = class_symbol.borrow();
|
let generic_parameters = class_symbol.generic_parameters();
|
||||||
let generic_parameters = borrowed_class_symbol.generic_parameters();
|
|
||||||
if generic_parameters.len() != self.generic_arguments.len() {
|
if generic_parameters.len() != self.generic_arguments.len() {
|
||||||
let diagnostic = Diagnostic::new(
|
let diagnostic = Diagnostic::new(
|
||||||
&format!(
|
&format!(
|
||||||
@ -111,7 +139,7 @@ impl TypeUse {
|
|||||||
|
|
||||||
// check that each arg is assignable to the param's extends
|
// check that each arg is assignable to the param's extends
|
||||||
for i in 0..self.generic_arguments.len() {
|
for i in 0..self.generic_arguments.len() {
|
||||||
let generic_parameter_symbol = generic_parameters[i].borrow();
|
let generic_parameter_symbol = &generic_parameters[i];
|
||||||
if generic_parameter_symbol.extends().len() > 0 {
|
if generic_parameter_symbol.extends().len() > 0 {
|
||||||
unimplemented!("Generic extends not implemented yet.")
|
unimplemented!("Generic extends not implemented yet.")
|
||||||
}
|
}
|
||||||
@ -153,6 +181,7 @@ mod tests {
|
|||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn type_check_generics() -> Result<(), Vec<Diagnostic>> {
|
fn type_check_generics() -> Result<(), Vec<Diagnostic>> {
|
||||||
@ -167,10 +196,12 @@ mod tests {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let mut types_table = TypesTable::new();
|
||||||
|
|
||||||
compilation_unit.gather_declared_names(&mut symbol_table)?;
|
compilation_unit.init_scopes(&mut symbol_table);
|
||||||
compilation_unit.check_name_usages(&mut symbol_table)?;
|
compilation_unit.gather_symbols_into(&mut symbol_table)?;
|
||||||
compilation_unit.type_check(&mut symbol_table)?;
|
compilation_unit.check_names(&mut symbol_table)?;
|
||||||
|
compilation_unit.type_check(&mut symbol_table, &mut types_table)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
pub type ErrorCode = usize;
|
pub type ErrorCode = usize;
|
||||||
|
|
||||||
|
pub const SYMBOL_NOT_FOUND: ErrorCode = 13;
|
||||||
pub const SYMBOL_ALREADY_DECLARED: ErrorCode = 14;
|
pub const SYMBOL_ALREADY_DECLARED: ErrorCode = 14;
|
||||||
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
||||||
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
|
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
|
||||||
@ -9,3 +10,8 @@ pub const INCORRECT_GENERIC_ARGUMENTS: ErrorCode = 19;
|
|||||||
pub const GENERIC_ARGUMENT_TYPE_MISMATCH: ErrorCode = 20;
|
pub const GENERIC_ARGUMENT_TYPE_MISMATCH: ErrorCode = 20;
|
||||||
pub const FIELD_MULTIPLE_INIT: ErrorCode = 21;
|
pub const FIELD_MULTIPLE_INIT: ErrorCode = 21;
|
||||||
pub const FIELD_UNINIT: ErrorCode = 22;
|
pub const FIELD_UNINIT: ErrorCode = 22;
|
||||||
|
pub const SELF_FIELD_USED_IN_INIT: ErrorCode = 23;
|
||||||
|
pub const SELF_METHOD_USED_IN_INIT: ErrorCode = 24;
|
||||||
|
pub const SELF_CONSTRUCTOR_USED_IN_INIT: ErrorCode = 25;
|
||||||
|
pub const OUTER_CLASS_FIELD_USED_IN_INIT: ErrorCode = 26;
|
||||||
|
pub const OUTER_CLASS_METHOD_USED_IN_INIT: ErrorCode = 27;
|
||||||
|
|||||||
@ -121,11 +121,13 @@ impl Display for IrBlock {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::parser::parse_compilation_unit;
|
use crate::parser::parse_compilation_unit;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::types_table::TypesTable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlapping_assignments_bug_when_k_2() {
|
fn overlapping_assignments_bug_when_k_2() -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut compilation_unit = parse_compilation_unit(
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
"
|
"
|
||||||
fn main()
|
fn main()
|
||||||
@ -138,15 +140,12 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
compilation_unit
|
let mut types_table = TypesTable::new();
|
||||||
.gather_declared_names(&mut symbol_table)
|
|
||||||
.expect("gather failed");
|
compilation_unit.init_scopes(&mut symbol_table);
|
||||||
compilation_unit
|
compilation_unit.gather_symbols_into(&mut symbol_table)?;
|
||||||
.check_name_usages(&mut symbol_table)
|
compilation_unit.check_names(&mut symbol_table)?;
|
||||||
.expect("name check failed");
|
compilation_unit.type_check(&mut symbol_table, &mut types_table)?;
|
||||||
compilation_unit
|
|
||||||
.type_check(&mut symbol_table)
|
|
||||||
.expect("type check failed");
|
|
||||||
|
|
||||||
let main = compilation_unit
|
let main = compilation_unit
|
||||||
.functions()
|
.functions()
|
||||||
@ -154,8 +153,10 @@ mod tests {
|
|||||||
.find(|f| f.declared_name() == "main")
|
.find(|f| f.declared_name() == "main")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut main_ir = main.to_ir(&symbol_table, None);
|
let mut main_ir = main.to_ir(&symbol_table, &types_table, None);
|
||||||
let (register_assignments, _) = main_ir.assign_registers(2);
|
let (register_assignments, _) = main_ir.assign_registers(2);
|
||||||
assert_eq!(register_assignments.len(), 4);
|
assert_eq!(register_assignments.len(), 4);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,9 +51,9 @@ impl IrField {
|
|||||||
TypeInfo::Integer => VmTypeInfo::Int,
|
TypeInfo::Integer => VmTypeInfo::Int,
|
||||||
TypeInfo::Double => VmTypeInfo::Double,
|
TypeInfo::Double => VmTypeInfo::Double,
|
||||||
TypeInfo::String => VmTypeInfo::String,
|
TypeInfo::String => VmTypeInfo::String,
|
||||||
TypeInfo::ClassInstance(class_symbol) => VmTypeInfo::ClassInstance(
|
TypeInfo::ClassInstance(class_symbol) => {
|
||||||
fqn_parts_to_string(class_symbol.borrow().fqn_parts()).into(),
|
VmTypeInfo::ClassInstance(fqn_parts_to_string(class_symbol.fqn_parts()).into())
|
||||||
),
|
}
|
||||||
TypeInfo::GenericType(_) => VmTypeInfo::Any,
|
TypeInfo::GenericType(_) => VmTypeInfo::Any,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub struct IrFunction {
|
|||||||
impl IrFunction {
|
impl IrFunction {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fqn: Rc<str>,
|
fqn: Rc<str>,
|
||||||
parameters: &[Rc<IrParameter>],
|
parameters: Vec<Rc<IrParameter>>,
|
||||||
return_type_info: &TypeInfo,
|
return_type_info: &TypeInfo,
|
||||||
entry: Rc<RefCell<IrBlock>>,
|
entry: Rc<RefCell<IrBlock>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|||||||
@ -5,9 +5,10 @@ pub mod error_codes;
|
|||||||
pub mod ir;
|
pub mod ir;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod scope;
|
pub mod scope;
|
||||||
pub mod source_range;
|
pub mod source_range;
|
||||||
pub mod symbol;
|
pub mod symbol;
|
||||||
pub mod symbol_table;
|
pub mod symbol_table;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod type_info;
|
pub mod type_info;
|
||||||
|
pub mod types_table;
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
use crate::symbol::variable_symbol::VariableSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct BlockScope {
|
pub struct BlockScope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: usize,
|
parent_id: usize,
|
||||||
variable_symbols: HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>>,
|
variable_symbols: HashMap<Rc<str>, Rc<VariableSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockScope {
|
impl BlockScope {
|
||||||
@ -18,11 +17,11 @@ impl BlockScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variable_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>> {
|
pub fn variable_symbols(&self) -> &HashMap<Rc<str>, Rc<VariableSymbol>> {
|
||||||
&self.variable_symbols
|
&self.variable_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variable_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>> {
|
pub fn variable_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<VariableSymbol>> {
|
||||||
&mut self.variable_symbols
|
&mut self.variable_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
64
dmc-lib/src/scope/class_body_scope.rs
Normal file
64
dmc-lib/src/scope/class_body_scope.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct ClassBodyScope {
|
||||||
|
debug_name: String,
|
||||||
|
parent_id: usize,
|
||||||
|
class_symbols: HashMap<Rc<str>, Rc<ClassSymbol>>,
|
||||||
|
field_symbols: HashMap<Rc<str>, Rc<FieldSymbol>>,
|
||||||
|
function_symbols: HashMap<Rc<str>, Rc<FunctionSymbol>>,
|
||||||
|
constructor_symbol: Option<Rc<ConstructorSymbol>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassBodyScope {
|
||||||
|
pub fn new(debug_name: &str, parent_id: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
debug_name: debug_name.into(),
|
||||||
|
parent_id,
|
||||||
|
class_symbols: HashMap::new(),
|
||||||
|
field_symbols: HashMap::new(),
|
||||||
|
function_symbols: HashMap::new(),
|
||||||
|
constructor_symbol: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<ClassSymbol>> {
|
||||||
|
&self.class_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<ClassSymbol>> {
|
||||||
|
&mut self.class_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_symbols(&self) -> &HashMap<Rc<str>, Rc<FieldSymbol>> {
|
||||||
|
&self.field_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<FieldSymbol>> {
|
||||||
|
&mut self.field_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<FunctionSymbol>> {
|
||||||
|
&self.function_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<FunctionSymbol>> {
|
||||||
|
&mut self.function_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constructor_symbol(&self) -> Option<&Rc<ConstructorSymbol>> {
|
||||||
|
self.constructor_symbol.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constructor_symbol_mut(&mut self) -> &mut Option<Rc<ConstructorSymbol>> {
|
||||||
|
&mut self.constructor_symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_id(&self) -> usize {
|
||||||
|
self.parent_id
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,20 +1,11 @@
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
|
||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ClassScope {
|
pub struct ClassScope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: usize,
|
parent_id: usize,
|
||||||
generic_parameter_symbols: HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>>,
|
generic_parameter_symbols: HashMap<Rc<str>, Rc<GenericParameterSymbol>>,
|
||||||
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
|
|
||||||
field_symbols: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
|
||||||
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
|
||||||
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassScope {
|
impl ClassScope {
|
||||||
@ -23,58 +14,20 @@ impl ClassScope {
|
|||||||
debug_name: debug_name.into(),
|
debug_name: debug_name.into(),
|
||||||
parent_id,
|
parent_id,
|
||||||
generic_parameter_symbols: HashMap::new(),
|
generic_parameter_symbols: HashMap::new(),
|
||||||
class_symbols: HashMap::new(),
|
|
||||||
field_symbols: HashMap::new(),
|
|
||||||
function_symbols: HashMap::new(),
|
|
||||||
constructor_symbol: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generic_parameter_symbols(
|
|
||||||
&self,
|
|
||||||
) -> &HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>> {
|
|
||||||
&self.generic_parameter_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generic_parameter_symbols_mut(
|
|
||||||
&mut self,
|
|
||||||
) -> &mut HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>> {
|
|
||||||
&mut self.generic_parameter_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
|
||||||
&self.class_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
|
||||||
&mut self.class_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
|
||||||
&self.field_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn field_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
|
||||||
&mut self.field_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
|
|
||||||
&self.function_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
|
|
||||||
&mut self.function_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constructor_symbol(&self) -> Option<&Rc<RefCell<ConstructorSymbol>>> {
|
|
||||||
self.constructor_symbol.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constructor_symbol_mut(&mut self) -> &mut Option<Rc<RefCell<ConstructorSymbol>>> {
|
|
||||||
&mut self.constructor_symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent_id(&self) -> usize {
|
pub fn parent_id(&self) -> usize {
|
||||||
self.parent_id
|
self.parent_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generic_parameter_symbols(&self) -> &HashMap<Rc<str>, Rc<GenericParameterSymbol>> {
|
||||||
|
&self.generic_parameter_symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generic_parameter_symbols_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut HashMap<Rc<str>, Rc<GenericParameterSymbol>> {
|
||||||
|
&mut self.generic_parameter_symbols
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct FunctionScope {
|
pub struct FunctionScope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: usize,
|
parent_id: usize,
|
||||||
parameter_symbols: HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>>,
|
parameter_symbols: HashMap<Rc<str>, Rc<ParameterSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionScope {
|
impl FunctionScope {
|
||||||
@ -18,11 +17,11 @@ impl FunctionScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameter_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>> {
|
pub fn parameter_symbols(&self) -> &HashMap<Rc<str>, Rc<ParameterSymbol>> {
|
||||||
&self.parameter_symbols
|
&self.parameter_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameter_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>> {
|
pub fn parameter_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<ParameterSymbol>> {
|
||||||
&mut self.parameter_symbols
|
&mut self.parameter_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
use crate::scope::block_scope::BlockScope;
|
use crate::scope::block_scope::BlockScope;
|
||||||
|
use crate::scope::class_body_scope::ClassBodyScope;
|
||||||
use crate::scope::class_scope::ClassScope;
|
use crate::scope::class_scope::ClassScope;
|
||||||
use crate::scope::function_scope::FunctionScope;
|
use crate::scope::function_scope::FunctionScope;
|
||||||
use crate::scope::module_scope::ModuleScope;
|
use crate::scope::module_scope::ModuleScope;
|
||||||
|
|
||||||
pub mod block_scope;
|
pub mod block_scope;
|
||||||
|
pub mod class_body_scope;
|
||||||
pub mod class_scope;
|
pub mod class_scope;
|
||||||
pub mod function_scope;
|
pub mod function_scope;
|
||||||
pub mod module_scope;
|
pub mod module_scope;
|
||||||
@ -11,6 +13,7 @@ pub mod module_scope;
|
|||||||
pub enum Scope {
|
pub enum Scope {
|
||||||
Module(ModuleScope),
|
Module(ModuleScope),
|
||||||
Class(ClassScope),
|
Class(ClassScope),
|
||||||
|
ClassBody(ClassBodyScope),
|
||||||
Function(FunctionScope),
|
Function(FunctionScope),
|
||||||
Block(BlockScope),
|
Block(BlockScope),
|
||||||
}
|
}
|
||||||
@ -20,6 +23,7 @@ impl Scope {
|
|||||||
match self {
|
match self {
|
||||||
Scope::Module(module_scope) => module_scope.parent_id(),
|
Scope::Module(module_scope) => module_scope.parent_id(),
|
||||||
Scope::Class(class_scope) => Some(class_scope.parent_id()),
|
Scope::Class(class_scope) => Some(class_scope.parent_id()),
|
||||||
|
Scope::ClassBody(class_body_scope) => Some(class_body_scope.parent_id()),
|
||||||
Scope::Function(function_scope) => Some(function_scope.parent_id()),
|
Scope::Function(function_scope) => Some(function_scope.parent_id()),
|
||||||
Scope::Block(block_scope) => Some(block_scope.parent_id()),
|
Scope::Block(block_scope) => Some(block_scope.parent_id()),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ModuleScope {
|
pub struct ModuleScope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: Option<usize>,
|
parent_id: Option<usize>,
|
||||||
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
|
class_symbols: HashMap<Rc<str>, Rc<ClassSymbol>>,
|
||||||
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
function_symbols: HashMap<Rc<str>, Rc<FunctionSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleScope {
|
impl ModuleScope {
|
||||||
@ -21,19 +20,19 @@ impl ModuleScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<ClassSymbol>> {
|
||||||
&self.class_symbols
|
&self.class_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
pub fn class_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<ClassSymbol>> {
|
||||||
&mut self.class_symbols
|
&mut self.class_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
|
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<FunctionSymbol>> {
|
||||||
&self.function_symbols
|
&self.function_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
|
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<FunctionSymbol>> {
|
||||||
&mut self.function_symbols
|
&mut self.function_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,34 +1,19 @@
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum CallableSymbol {
|
pub enum CallableSymbol {
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<FunctionSymbol>),
|
||||||
Class(Rc<RefCell<ClassSymbol>>),
|
Class(Rc<ClassSymbol>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallableSymbol {
|
impl CallableSymbol {
|
||||||
pub fn return_type_info(&self) -> TypeInfo {
|
pub fn parameters(&self) -> Vec<Rc<ParameterSymbol>> {
|
||||||
match self {
|
match self {
|
||||||
CallableSymbol::Function(function) => function.borrow().return_type_info().clone(),
|
CallableSymbol::Function(function_symbol) => function_symbol.parameters().to_vec(),
|
||||||
CallableSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parameters(&self) -> Vec<Rc<RefCell<ParameterSymbol>>> {
|
|
||||||
match self {
|
|
||||||
CallableSymbol::Function(function_symbol) => {
|
|
||||||
function_symbol.borrow().parameters().to_vec()
|
|
||||||
}
|
|
||||||
CallableSymbol::Class(class_symbol) => {
|
CallableSymbol::Class(class_symbol) => {
|
||||||
if let Some(constructor_symbol) = class_symbol.borrow().constructor_symbol() {
|
class_symbol.constructor_symbol().parameters().to_vec()
|
||||||
constructor_symbol.borrow().parameters().to_vec()
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ClassSymbol {
|
pub struct ClassSymbol {
|
||||||
@ -13,74 +12,92 @@ pub struct ClassSymbol {
|
|||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
generic_parameters: Vec<Rc<RefCell<GenericParameterSymbol>>>,
|
scope_id: usize,
|
||||||
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
generic_parameters: Vec<Rc<GenericParameterSymbol>>,
|
||||||
fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
constructor_symbol: Rc<ConstructorSymbol>,
|
||||||
functions: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
fields: HashMap<Rc<str>, Rc<FieldSymbol>>,
|
||||||
|
functions: HashMap<Rc<str>, Rc<FunctionSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassSymbol {
|
impl ClassSymbol {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
declared_name: &Rc<str>,
|
declared_name: &Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: &SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
|
scope_id: usize,
|
||||||
|
generic_parameters: Vec<Rc<GenericParameterSymbol>>,
|
||||||
|
constructor_symbol: Rc<ConstructorSymbol>,
|
||||||
|
fields: Vec<Rc<FieldSymbol>>,
|
||||||
|
functions: Vec<Rc<FunctionSymbol>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.clone(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range: declared_name_source_range.clone(),
|
||||||
fqn_parts,
|
fqn_parts,
|
||||||
is_extern,
|
is_extern,
|
||||||
generic_parameters: vec![],
|
scope_id,
|
||||||
constructor_symbol: None,
|
generic_parameters,
|
||||||
fields: HashMap::new(),
|
constructor_symbol,
|
||||||
functions: HashMap::new(),
|
fields: fields
|
||||||
|
.into_iter()
|
||||||
|
.map(|fs| (fs.declared_name_owned(), fs))
|
||||||
|
.collect(),
|
||||||
|
functions: functions
|
||||||
|
.into_iter()
|
||||||
|
.map(|fs| (fs.declared_name_owned(), fs))
|
||||||
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.declared_name_source_range
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
||||||
&self.fqn_parts
|
&self.fqn_parts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_generic_parameters(
|
pub fn scope_id(&self) -> usize {
|
||||||
&mut self,
|
self.scope_id
|
||||||
generic_parameters: Vec<Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
) {
|
|
||||||
self.generic_parameters = generic_parameters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generic_parameters(&self) -> &[Rc<RefCell<GenericParameterSymbol>>] {
|
pub fn generic_parameters(&self) -> &[Rc<GenericParameterSymbol>] {
|
||||||
&self.generic_parameters
|
&self.generic_parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_constructor_symbol(&mut self, constructor_symbol: Rc<RefCell<ConstructorSymbol>>) {
|
pub fn constructor_symbol(&self) -> &ConstructorSymbol {
|
||||||
self.constructor_symbol = Some(constructor_symbol);
|
&self.constructor_symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fields(&mut self, fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>) {
|
pub fn fields(&self) -> &HashMap<Rc<str>, Rc<FieldSymbol>> {
|
||||||
self.fields = fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fields(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
|
||||||
&self.fields
|
&self.fields
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A value of `None` indicates that there is no declared constructor for this class.
|
pub fn functions(&self) -> &HashMap<Rc<str>, Rc<FunctionSymbol>> {
|
||||||
pub fn constructor_symbol(&self) -> Option<&Rc<RefCell<ConstructorSymbol>>> {
|
&self.functions
|
||||||
self.constructor_symbol.as_ref()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for ClassSymbol {
|
impl Eq for ClassSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for ClassSymbol {
|
||||||
self.declared_name.clone()
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.declared_name_source_range
|
|
||||||
|
impl Hash for ClassSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use std::cell::RefCell;
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ConstructorSymbol {
|
pub struct ConstructorSymbol {
|
||||||
@ -9,35 +8,51 @@ pub struct ConstructorSymbol {
|
|||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
is_default: bool,
|
is_default: bool,
|
||||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
scope_id: usize,
|
||||||
|
parameters: Vec<Rc<ParameterSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructorSymbol {
|
impl ConstructorSymbol {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
keyword_source_range: SourceRange,
|
keyword_source_range: &SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
is_default: bool,
|
is_default: bool,
|
||||||
|
scope_id: usize,
|
||||||
|
parameters: Vec<Rc<ParameterSymbol>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
keyword_source_range,
|
keyword_source_range: keyword_source_range.clone(),
|
||||||
fqn_parts,
|
fqn_parts,
|
||||||
is_extern,
|
is_extern,
|
||||||
is_default,
|
is_default,
|
||||||
parameters: None,
|
scope_id,
|
||||||
|
parameters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
"ctor"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
Rc::from(self.declared_name())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.keyword_source_range
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
||||||
&self.fqn_parts
|
&self.fqn_parts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
pub fn scope_id(&self) -> usize {
|
||||||
self.parameters = Some(parameters);
|
self.scope_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
|
pub fn parameters(&self) -> &[Rc<ParameterSymbol>] {
|
||||||
self.parameters.as_ref().unwrap()
|
&self.parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_extern(&self) -> bool {
|
pub fn is_extern(&self) -> bool {
|
||||||
@ -45,16 +60,16 @@ impl ConstructorSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for ConstructorSymbol {
|
impl Eq for ConstructorSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
"ctor"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for ConstructorSymbol {
|
||||||
Rc::from(self.declared_name())
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.keyword_source_range
|
|
||||||
|
impl Hash for ConstructorSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,111 +1,36 @@
|
|||||||
use crate::ast::ir_builder::IrBuilder;
|
|
||||||
use crate::ast::ir_util::get_or_init_field_pointer_variable;
|
|
||||||
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::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::symbol::variable_symbol::VariableSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum ExpressibleSymbol {
|
pub enum ExpressibleSymbol {
|
||||||
Class(Rc<RefCell<ClassSymbol>>),
|
Class(Rc<ClassSymbol>),
|
||||||
Field(Rc<RefCell<FieldSymbol>>),
|
Field(Rc<FieldSymbol>),
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<FunctionSymbol>),
|
||||||
Parameter(Rc<RefCell<ParameterSymbol>>),
|
Parameter(Rc<ParameterSymbol>),
|
||||||
Variable(Rc<RefCell<VariableSymbol>>),
|
Variable(Rc<VariableSymbol>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExpressibleSymbol {
|
impl ExpressibleSymbol {
|
||||||
pub fn type_info(&self) -> TypeInfo {
|
|
||||||
match self {
|
|
||||||
ExpressibleSymbol::Class(class_symbol) => TypeInfo::ClassInstance(class_symbol.clone()),
|
|
||||||
ExpressibleSymbol::Field(field_symbol) => field_symbol.borrow().type_info().clone(),
|
|
||||||
ExpressibleSymbol::Function(function_symbol) => {
|
|
||||||
TypeInfo::Function(function_symbol.clone()) // n.b. not the return type!
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
|
||||||
parameter_symbol.borrow().type_info().clone()
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
|
||||||
variable_symbol.borrow().type_info().clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_mut(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
ExpressibleSymbol::Field(field_symbol) => field_symbol.borrow().is_mut(),
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.borrow().is_mut(),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_range(&self) -> SourceRange {
|
pub fn source_range(&self) -> SourceRange {
|
||||||
match self {
|
match self {
|
||||||
ExpressibleSymbol::Class(class_symbol) => {
|
ExpressibleSymbol::Class(class_symbol) => {
|
||||||
class_symbol.borrow().declared_name_source_range().clone()
|
class_symbol.declared_name_source_range().clone()
|
||||||
}
|
}
|
||||||
ExpressibleSymbol::Field(field_symbol) => {
|
ExpressibleSymbol::Field(field_symbol) => {
|
||||||
field_symbol.borrow().declared_name_source_range().clone()
|
field_symbol.declared_name_source_range().clone()
|
||||||
}
|
}
|
||||||
ExpressibleSymbol::Function(function_symbol) => function_symbol
|
ExpressibleSymbol::Function(function_symbol) => {
|
||||||
.borrow()
|
function_symbol.declared_name_source_range().clone()
|
||||||
.declared_name_source_range()
|
|
||||||
.clone(),
|
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => parameter_symbol
|
|
||||||
.borrow()
|
|
||||||
.declared_name_source_range()
|
|
||||||
.clone(),
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol
|
|
||||||
.borrow()
|
|
||||||
.declared_name_source_range()
|
|
||||||
.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ir_expression(&self, builder: &mut IrBuilder) -> IrExpression {
|
|
||||||
match self {
|
|
||||||
ExpressibleSymbol::Class(class_symbol) => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Field(field_symbol) => {
|
|
||||||
// now we need to read the field into a variable and return an expression pointing
|
|
||||||
// to that variable
|
|
||||||
let read_destination = IrVariable::new_vr(
|
|
||||||
builder.new_t_var().into(),
|
|
||||||
builder.current_block().id(),
|
|
||||||
field_symbol.borrow().type_info(),
|
|
||||||
);
|
|
||||||
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
|
|
||||||
let ir_read_field = IrReadField::new(
|
|
||||||
get_or_init_field_pointer_variable(builder, field_symbol).clone(),
|
|
||||||
);
|
|
||||||
builder
|
|
||||||
.current_block_mut()
|
|
||||||
.add_statement(IrStatement::Assign(IrAssign::new(
|
|
||||||
read_destination_as_rc.clone(),
|
|
||||||
IrOperation::ReadField(ir_read_field),
|
|
||||||
)));
|
|
||||||
IrExpression::Variable(read_destination_as_rc)
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Function(_) => {
|
|
||||||
panic!("Cannot get ir_variable for FunctionSymbol");
|
|
||||||
}
|
}
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||||
IrExpression::Parameter(parameter_symbol.borrow().ir_parameter().clone())
|
parameter_symbol.declared_name_source_range().clone()
|
||||||
}
|
}
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||||
IrExpression::Variable(variable_symbol.borrow().vr_variable().clone())
|
variable_symbol.declared_name_source_range().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct FieldSymbol {
|
pub struct FieldSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
is_mut: bool,
|
is_mut: bool,
|
||||||
|
scope_id: usize,
|
||||||
type_info: Option<TypeInfo>,
|
type_info: Option<TypeInfo>,
|
||||||
field_index: Option<usize>,
|
field_index: Option<usize>,
|
||||||
}
|
}
|
||||||
@ -16,16 +17,34 @@ impl FieldSymbol {
|
|||||||
declared_name: &Rc<str>,
|
declared_name: &Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
is_mut: bool,
|
is_mut: bool,
|
||||||
|
scope_id: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.clone(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
is_mut,
|
is_mut,
|
||||||
|
scope_id,
|
||||||
type_info: None,
|
type_info: None,
|
||||||
field_index: None,
|
field_index: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.declared_name_source_range
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> usize {
|
||||||
|
self.scope_id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_mut(&self) -> bool {
|
pub fn is_mut(&self) -> bool {
|
||||||
self.is_mut
|
self.is_mut
|
||||||
}
|
}
|
||||||
@ -47,16 +66,17 @@ impl FieldSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for FieldSymbol {
|
impl Eq for FieldSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for FieldSymbol {
|
||||||
self.declared_name.clone()
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.declared_name_source_range
|
|
||||||
|
impl Hash for FieldSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::type_info::TypeInfo;
|
use std::hash::Hash;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct FunctionSymbol {
|
pub struct FunctionSymbol {
|
||||||
@ -10,45 +8,57 @@ pub struct FunctionSymbol {
|
|||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
is_method: bool,
|
||||||
return_type: Option<TypeInfo>,
|
scope_id: usize,
|
||||||
|
parameters: Vec<Rc<ParameterSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionSymbol {
|
impl FunctionSymbol {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
declared_name: &str,
|
declared_name: &Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
|
is_method: bool,
|
||||||
|
scope_id: usize,
|
||||||
|
parameters: Vec<Rc<ParameterSymbol>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
fqn_parts,
|
fqn_parts,
|
||||||
is_extern,
|
is_extern,
|
||||||
parameters: None,
|
is_method,
|
||||||
return_type: None,
|
scope_id,
|
||||||
|
parameters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.declared_name_source_range
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
pub fn fqn_parts(&self) -> &[Rc<str>] {
|
||||||
&self.fqn_parts
|
&self.fqn_parts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
pub fn is_method(&self) -> bool {
|
||||||
self.parameters = Some(parameters);
|
self.is_method
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
|
pub fn scope_id(&self) -> usize {
|
||||||
self.parameters.as_ref().unwrap()
|
self.scope_id
|
||||||
}
|
}
|
||||||
|
pub fn parameters(&self) -> &[Rc<ParameterSymbol>] {
|
||||||
pub fn set_return_type_info(&mut self, return_type: TypeInfo) {
|
&self.parameters
|
||||||
self.return_type = Some(return_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn return_type_info(&self) -> &TypeInfo {
|
|
||||||
self.return_type.as_ref().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_extern(&self) -> bool {
|
pub fn is_extern(&self) -> bool {
|
||||||
@ -56,16 +66,17 @@ impl FunctionSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for FunctionSymbol {
|
impl Eq for FunctionSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for FunctionSymbol {
|
||||||
self.declared_name.clone()
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.declared_name_source_range
|
|
||||||
|
impl Hash for FunctionSymbol {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,45 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct GenericParameterSymbol {
|
pub struct GenericParameterSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
scope_id: usize,
|
||||||
extends: Option<Vec<TypeInfo>>,
|
extends: Option<Vec<TypeInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericParameterSymbol {
|
impl GenericParameterSymbol {
|
||||||
pub fn new(declared_name: &Rc<str>, declared_name_source_range: &SourceRange) -> Self {
|
pub fn new(
|
||||||
|
declared_name: &Rc<str>,
|
||||||
|
declared_name_source_range: &SourceRange,
|
||||||
|
scope_id: usize,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.clone(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range: declared_name_source_range.clone(),
|
declared_name_source_range: declared_name_source_range.clone(),
|
||||||
|
scope_id,
|
||||||
extends: None,
|
extends: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.declared_name_source_range
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> usize {
|
||||||
|
self.scope_id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_extends(&mut self, extends: Vec<TypeInfo>) {
|
pub fn set_extends(&mut self, extends: Vec<TypeInfo>) {
|
||||||
self.extends = Some(extends);
|
self.extends = Some(extends);
|
||||||
}
|
}
|
||||||
@ -27,16 +49,17 @@ impl GenericParameterSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for GenericParameterSymbol {
|
impl Eq for GenericParameterSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for GenericParameterSymbol {
|
||||||
self.declared_name.clone()
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.declared_name_source_range
|
|
||||||
|
impl Hash for GenericParameterSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
|
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::variable_symbol::VariableSymbol;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub mod callable_symbol;
|
pub mod callable_symbol;
|
||||||
@ -12,8 +19,59 @@ pub mod parameter_symbol;
|
|||||||
pub mod type_symbol;
|
pub mod type_symbol;
|
||||||
pub mod variable_symbol;
|
pub mod variable_symbol;
|
||||||
|
|
||||||
pub trait Symbol {
|
#[derive(Eq, PartialEq, Hash)]
|
||||||
fn declared_name(&self) -> &str;
|
pub enum Symbol {
|
||||||
fn declared_name_owned(&self) -> Rc<str>;
|
Class(Rc<ClassSymbol>),
|
||||||
fn declared_name_source_range(&self) -> &SourceRange;
|
GenericParameter(Rc<GenericParameterSymbol>),
|
||||||
|
Field(Rc<FieldSymbol>),
|
||||||
|
Constructor(Rc<ConstructorSymbol>),
|
||||||
|
Function(Rc<FunctionSymbol>),
|
||||||
|
Parameter(Rc<ParameterSymbol>),
|
||||||
|
Variable(Rc<VariableSymbol>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
pub fn scope_id(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Symbol::Class(class_symbol) => class_symbol.scope_id(),
|
||||||
|
Symbol::GenericParameter(generic_parameter_symbol) => {
|
||||||
|
generic_parameter_symbol.scope_id()
|
||||||
|
}
|
||||||
|
Symbol::Field(field_symbol) => field_symbol.scope_id(),
|
||||||
|
Symbol::Constructor(constructor_symbol) => constructor_symbol.scope_id(),
|
||||||
|
Symbol::Function(function_symbol) => function_symbol.scope_id(),
|
||||||
|
Symbol::Parameter(parameter_symbol) => parameter_symbol.scope_id(),
|
||||||
|
Symbol::Variable(variable_symbol) => variable_symbol.scope_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Symbol::Class(class_symbol) => class_symbol.declared_name(),
|
||||||
|
Symbol::GenericParameter(generic_parameter_symbol) => {
|
||||||
|
generic_parameter_symbol.declared_name()
|
||||||
|
}
|
||||||
|
Symbol::Field(field_symbol) => field_symbol.declared_name(),
|
||||||
|
Symbol::Constructor(constructor_symbol) => constructor_symbol.declared_name(),
|
||||||
|
Symbol::Function(function_symbol) => function_symbol.declared_name(),
|
||||||
|
Symbol::Parameter(parameter_symbol) => parameter_symbol.declared_name(),
|
||||||
|
Symbol::Variable(variable_symbol) => variable_symbol.declared_name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
match self {
|
||||||
|
Symbol::Class(class_symbol) => class_symbol.declared_name_source_range(),
|
||||||
|
Symbol::GenericParameter(generic_parameter_symbol) => {
|
||||||
|
generic_parameter_symbol.declared_name_source_range()
|
||||||
|
}
|
||||||
|
Symbol::Field(field_symbol) => field_symbol.declared_name_source_range(),
|
||||||
|
Symbol::Constructor(constructor_symbol) => {
|
||||||
|
constructor_symbol.declared_name_source_range()
|
||||||
|
}
|
||||||
|
Symbol::Function(function_symbol) => function_symbol.declared_name_source_range(),
|
||||||
|
Symbol::Parameter(parameter_symbol) => parameter_symbol.declared_name_source_range(),
|
||||||
|
Symbol::Variable(variable_symbol) => variable_symbol.declared_name_source_range(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,53 +1,54 @@
|
|||||||
use crate::ir::ir_parameter::IrParameter;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
use std::hash::{Hash, Hasher};
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ParameterSymbol {
|
pub struct ParameterSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
type_info: Option<TypeInfo>,
|
scope_id: usize,
|
||||||
ir_parameter: Option<Rc<IrParameter>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParameterSymbol {
|
impl ParameterSymbol {
|
||||||
pub fn new(declared_name: &Rc<str>, declared_name_source_range: SourceRange) -> Self {
|
pub fn new(
|
||||||
|
declared_name: &Rc<str>,
|
||||||
|
declared_name_source_range: SourceRange,
|
||||||
|
scope_id: usize,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.clone(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
type_info: None,
|
scope_id,
|
||||||
ir_parameter: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
pub fn declared_name(&self) -> &str {
|
||||||
self.type_info = Some(type_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
|
||||||
self.type_info.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ir_parameter(&mut self, ir_parameter: Rc<IrParameter>) {
|
|
||||||
self.ir_parameter = Some(ir_parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ir_parameter(&self) -> &Rc<IrParameter> {
|
|
||||||
self.ir_parameter.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Symbol for ParameterSymbol {
|
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
self.declared_name.clone()
|
self.declared_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
&self.declared_name_source_range
|
&self.declared_name_source_range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scope_id(&self) -> usize {
|
||||||
|
self.scope_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for ParameterSymbol {}
|
||||||
|
|
||||||
|
impl PartialEq for ParameterSymbol {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for ParameterSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum TypeSymbol {
|
pub enum TypeSymbol {
|
||||||
Class(Rc<RefCell<ClassSymbol>>),
|
Class(Rc<ClassSymbol>),
|
||||||
GenericParameter(Rc<RefCell<GenericParameterSymbol>>),
|
GenericParameter(Rc<GenericParameterSymbol>),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,64 +1,61 @@
|
|||||||
use crate::ir::ir_variable::IrVariable;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
use std::hash::{Hash, Hasher};
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct VariableSymbol {
|
pub struct VariableSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
is_mut: bool,
|
is_mut: bool,
|
||||||
type_info: Option<TypeInfo>,
|
scope_id: usize,
|
||||||
vr_variable: Option<Rc<RefCell<IrVariable>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableSymbol {
|
impl VariableSymbol {
|
||||||
pub fn new(name: &Rc<str>, declared_name_source_range: SourceRange, is_mut: bool) -> Self {
|
pub fn new(
|
||||||
|
name: &Rc<str>,
|
||||||
|
declared_name_source_range: &SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
|
scope_id: usize,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: name.clone(),
|
declared_name: name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range: declared_name_source_range.clone(),
|
||||||
is_mut,
|
is_mut,
|
||||||
type_info: None,
|
scope_id,
|
||||||
vr_variable: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn declared_name(&self) -> &str {
|
||||||
|
&self.declared_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_owned(&self) -> Rc<str> {
|
||||||
|
self.declared_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declared_name_source_range(&self) -> &SourceRange {
|
||||||
|
&self.declared_name_source_range
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_mut(&self) -> bool {
|
pub fn is_mut(&self) -> bool {
|
||||||
self.is_mut
|
self.is_mut
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
pub fn scope_id(&self) -> usize {
|
||||||
self.type_info = Some(type_info);
|
self.scope_id
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
|
||||||
self.type_info
|
|
||||||
.as_ref()
|
|
||||||
.expect("TypeInfo not initialized. Did you type check?")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_vr_variable(&mut self, ir_variable: Rc<RefCell<IrVariable>>) {
|
|
||||||
self.vr_variable = Some(ir_variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vr_variable(&self) -> &Rc<RefCell<IrVariable>> {
|
|
||||||
self.vr_variable
|
|
||||||
.as_ref()
|
|
||||||
.expect("ir_variable not yet initialized")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol for VariableSymbol {
|
impl Eq for VariableSymbol {}
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
impl PartialEq for VariableSymbol {
|
||||||
self.declared_name.clone()
|
fn eq(&self, other: &Self) -> bool {
|
||||||
}
|
self.declared_name == other.declared_name && self.scope_id == other.scope_id
|
||||||
|
}
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
}
|
||||||
&self.declared_name_source_range
|
|
||||||
|
impl Hash for VariableSymbol {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.declared_name.hash(state);
|
||||||
|
self.scope_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,134 +1,210 @@
|
|||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::scope::block_scope::BlockScope;
|
use crate::scope::block_scope::BlockScope;
|
||||||
|
use crate::scope::class_body_scope::ClassBodyScope;
|
||||||
use crate::scope::class_scope::ClassScope;
|
use crate::scope::class_scope::ClassScope;
|
||||||
use crate::scope::function_scope::FunctionScope;
|
use crate::scope::function_scope::FunctionScope;
|
||||||
use crate::scope::module_scope::ModuleScope;
|
use crate::scope::module_scope::ModuleScope;
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
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::type_symbol::TypeSymbol;
|
||||||
use std::cell::RefCell;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub fn find_in_module_by_name(
|
fn find_class_symbol_ref(
|
||||||
module_scope: &ModuleScope,
|
symbols: &HashMap<Rc<str>, Rc<ClassSymbol>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<Rc<RefCell<dyn Symbol>>> {
|
) -> Option<Symbol> {
|
||||||
module_scope
|
symbols
|
||||||
.function_symbols()
|
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
.map(|symbol| Symbol::Class(symbol.clone()))
|
||||||
.or_else(|| {
|
|
||||||
module_scope
|
|
||||||
.class_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_in_class_by_name(
|
fn find_generic_parameter_symbol_ref(
|
||||||
class_scope: &ClassScope,
|
symbols: &HashMap<Rc<str>, Rc<GenericParameterSymbol>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<Rc<RefCell<dyn Symbol>>> {
|
) -> Option<Symbol> {
|
||||||
class_scope
|
symbols
|
||||||
.class_symbols()
|
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
.map(|symbol| Symbol::GenericParameter(symbol.clone()))
|
||||||
.or_else(|| {
|
|
||||||
class_scope
|
|
||||||
.function_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
class_scope
|
|
||||||
.field_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_in_function_by_name(
|
fn find_field_symbol_ref(
|
||||||
function_scope: &FunctionScope,
|
symbols: &HashMap<Rc<str>, Rc<FieldSymbol>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<Rc<RefCell<dyn Symbol>>> {
|
) -> Option<Symbol> {
|
||||||
function_scope
|
symbols
|
||||||
.parameter_symbols()
|
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
.map(|symbol| Symbol::Field(symbol.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_in_block_by_name(
|
fn find_function_symbol_ref(
|
||||||
block_scope: &BlockScope,
|
symbols: &HashMap<Rc<str>, Rc<FunctionSymbol>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<Rc<RefCell<dyn Symbol>>> {
|
) -> Option<Symbol> {
|
||||||
block_scope
|
symbols
|
||||||
.variable_symbols()
|
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|symbol| symbol.clone() as Rc<RefCell<dyn Symbol>>)
|
.map(|symbol| Symbol::Function(symbol.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_parameter_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<ParameterSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Symbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| Symbol::Parameter(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_variable_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<VariableSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Symbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| Symbol::Variable(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expressible symbol refs */
|
||||||
|
|
||||||
|
fn find_class_expressible_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<ClassSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<ExpressibleSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| ExpressibleSymbol::Class(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_field_expressible_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<FieldSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<ExpressibleSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| ExpressibleSymbol::Field(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_function_expressible_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<FunctionSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<ExpressibleSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| ExpressibleSymbol::Function(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_parameter_expressible_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<ParameterSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<ExpressibleSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| ExpressibleSymbol::Parameter(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_variable_expressible_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<VariableSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<ExpressibleSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| ExpressibleSymbol::Variable(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find type symbols */
|
||||||
|
|
||||||
|
fn find_class_type_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<ClassSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<TypeSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_generic_parameter_type_symbol_ref(
|
||||||
|
symbols: &HashMap<Rc<str>, Rc<GenericParameterSymbol>>,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<TypeSymbol> {
|
||||||
|
symbols
|
||||||
|
.get(name)
|
||||||
|
.map(|symbol| TypeSymbol::GenericParameter(symbol.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public helper functions */
|
||||||
|
/* Various find in functions */
|
||||||
|
|
||||||
|
pub fn find_in_module_by_name(module_scope: &ModuleScope, name: &str) -> Option<Symbol> {
|
||||||
|
find_function_symbol_ref(&module_scope.function_symbols(), name)
|
||||||
|
.or_else(|| find_class_symbol_ref(&module_scope.class_symbols(), name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_in_class_by_name(class_scope: &ClassScope, name: &str) -> Option<Symbol> {
|
||||||
|
find_generic_parameter_symbol_ref(&class_scope.generic_parameter_symbols(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_in_class_body_by_name(class_body_scope: &ClassBodyScope, name: &str) -> Option<Symbol> {
|
||||||
|
find_class_symbol_ref(&class_body_scope.class_symbols(), name)
|
||||||
|
.or_else(|| find_function_symbol_ref(&class_body_scope.function_symbols(), name))
|
||||||
|
.or_else(|| find_field_symbol_ref(&class_body_scope.field_symbols(), name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_in_function_by_name(function_scope: &FunctionScope, name: &str) -> Option<Symbol> {
|
||||||
|
find_parameter_symbol_ref(&function_scope.parameter_symbols(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_in_block_by_name(block_scope: &BlockScope, name: &str) -> Option<Symbol> {
|
||||||
|
find_variable_symbol_ref(&block_scope.variable_symbols(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find expressible */
|
||||||
|
|
||||||
fn find_expressible_in_module_by_name(
|
fn find_expressible_in_module_by_name(
|
||||||
module_scope: &ModuleScope,
|
module_scope: &ModuleScope,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<ExpressibleSymbol> {
|
) -> Option<ExpressibleSymbol> {
|
||||||
module_scope
|
find_class_expressible_symbol_ref(&module_scope.class_symbols(), name)
|
||||||
.class_symbols()
|
.or_else(|| find_function_expressible_symbol_ref(&module_scope.function_symbols(), name))
|
||||||
.get(name)
|
|
||||||
.map(|class_symbol| ExpressibleSymbol::Class(class_symbol.clone()))
|
|
||||||
.or_else(|| {
|
|
||||||
module_scope
|
|
||||||
.function_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone()))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_expressible_in_class_by_name(
|
fn find_expressible_in_class_body_by_name(
|
||||||
class_scope: &ClassScope,
|
class_body_scope: &ClassBodyScope,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<ExpressibleSymbol> {
|
) -> Option<ExpressibleSymbol> {
|
||||||
class_scope
|
find_class_expressible_symbol_ref(&class_body_scope.class_symbols(), name)
|
||||||
.class_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|symbol| ExpressibleSymbol::Class(symbol.clone()))
|
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
class_scope
|
find_function_expressible_symbol_ref(&class_body_scope.function_symbols(), name)
|
||||||
.function_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|function_symbol| ExpressibleSymbol::Function(function_symbol.clone()))
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
class_scope
|
|
||||||
.field_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|field_symbol| ExpressibleSymbol::Field(field_symbol.clone()))
|
|
||||||
})
|
})
|
||||||
|
.or_else(|| find_field_expressible_symbol_ref(&class_body_scope.field_symbols(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_expressible_in_function_by_name(
|
fn find_expressible_in_function_by_name(
|
||||||
function_scope: &FunctionScope,
|
function_scope: &FunctionScope,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<ExpressibleSymbol> {
|
) -> Option<ExpressibleSymbol> {
|
||||||
function_scope
|
find_parameter_expressible_symbol_ref(function_scope.parameter_symbols(), name)
|
||||||
.parameter_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|parameter_symbol| ExpressibleSymbol::Parameter(parameter_symbol.clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_expressible_in_block_by_name(
|
fn find_expressible_in_block_by_name(
|
||||||
block_scope: &BlockScope,
|
block_scope: &BlockScope,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Option<ExpressibleSymbol> {
|
) -> Option<ExpressibleSymbol> {
|
||||||
block_scope
|
find_variable_expressible_symbol_ref(block_scope.variable_symbols(), name)
|
||||||
.variable_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|variable_symbol| ExpressibleSymbol::Variable(variable_symbol.clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleSymbol> {
|
pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleSymbol> {
|
||||||
match scope {
|
match scope {
|
||||||
Scope::Module(module_scope) => find_expressible_in_module_by_name(module_scope, name),
|
Scope::Module(module_scope) => find_expressible_in_module_by_name(module_scope, name),
|
||||||
Scope::Class(class_scope) => find_expressible_in_class_by_name(class_scope, name),
|
Scope::Class(_) => None,
|
||||||
|
Scope::ClassBody(class_body_scope) => {
|
||||||
|
find_expressible_in_class_body_by_name(class_body_scope, name)
|
||||||
|
}
|
||||||
Scope::Function(function_scope) => {
|
Scope::Function(function_scope) => {
|
||||||
find_expressible_in_function_by_name(function_scope, name)
|
find_expressible_in_function_by_name(function_scope, name)
|
||||||
}
|
}
|
||||||
@ -136,32 +212,30 @@ pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find type */
|
||||||
|
|
||||||
fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option<TypeSymbol> {
|
fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option<TypeSymbol> {
|
||||||
module_scope
|
find_class_type_symbol_ref(&module_scope.class_symbols(), name)
|
||||||
.class_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
fn find_type_symbol_in_class_body(
|
||||||
class_scope
|
class_body_scope: &ClassBodyScope,
|
||||||
.class_symbols()
|
name: &str,
|
||||||
.get(name)
|
) -> Option<TypeSymbol> {
|
||||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
find_class_type_symbol_ref(&class_body_scope.class_symbols(), name)
|
||||||
.or_else(|| {
|
}
|
||||||
class_scope
|
|
||||||
.generic_parameter_symbols()
|
fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
||||||
.get(name)
|
find_generic_parameter_type_symbol_ref(&class_scope.generic_parameter_symbols(), name)
|
||||||
.map(|generic_parameter_symbol| {
|
|
||||||
TypeSymbol::GenericParameter(generic_parameter_symbol.clone())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
||||||
match scope {
|
match scope {
|
||||||
Scope::Module(module_scope) => find_type_symbol_in_module(module_scope, name),
|
Scope::Module(module_scope) => find_type_symbol_in_module(module_scope, name),
|
||||||
Scope::Class(class_scope) => find_type_symbol_in_class(class_scope, name),
|
Scope::Class(class_scope) => find_type_symbol_in_class(class_scope, name),
|
||||||
|
Scope::ClassBody(class_body_scope) => {
|
||||||
|
find_type_symbol_in_class_body(class_body_scope, name)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ mod helpers;
|
|||||||
|
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::scope::block_scope::BlockScope;
|
use crate::scope::block_scope::BlockScope;
|
||||||
|
use crate::scope::class_body_scope::ClassBodyScope;
|
||||||
use crate::scope::class_scope::ClassScope;
|
use crate::scope::class_scope::ClassScope;
|
||||||
use crate::scope::function_scope::FunctionScope;
|
use crate::scope::function_scope::FunctionScope;
|
||||||
use crate::scope::module_scope::ModuleScope;
|
use crate::scope::module_scope::ModuleScope;
|
||||||
@ -16,10 +17,9 @@ use crate::symbol::parameter_symbol::ParameterSymbol;
|
|||||||
use crate::symbol::type_symbol::TypeSymbol;
|
use crate::symbol::type_symbol::TypeSymbol;
|
||||||
use crate::symbol::variable_symbol::VariableSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::symbol_table::helpers::{
|
use crate::symbol_table::helpers::{
|
||||||
find_expressible_symbol, find_in_block_by_name, find_in_class_by_name,
|
find_expressible_symbol, find_in_block_by_name, find_in_class_body_by_name,
|
||||||
find_in_function_by_name, find_in_module_by_name, find_type_symbol, find_type_symbol_in_class,
|
find_in_class_by_name, find_in_function_by_name, find_in_module_by_name, find_type_symbol,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
@ -39,282 +39,210 @@ impl SymbolTable {
|
|||||||
self.scopes.len()
|
self.scopes.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_scope(&mut self, scope: Scope) {
|
fn push_scope(&mut self, scope: Scope) -> usize {
|
||||||
let scope_id = self.new_scope_id();
|
let scope_id = self.new_scope_id();
|
||||||
self.scopes.push(scope);
|
self.scopes.push(scope);
|
||||||
self.current_scope_id = Some(scope_id);
|
self.current_scope_id = Some(scope_id);
|
||||||
|
scope_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_module_scope(&mut self, debug_name: &str) {
|
pub fn push_module_scope(&mut self, debug_name: &str) -> usize {
|
||||||
self.push_scope(Scope::Module(ModuleScope::new(
|
self.push_scope(Scope::Module(ModuleScope::new(
|
||||||
debug_name,
|
debug_name,
|
||||||
self.current_scope_id,
|
self.current_scope_id,
|
||||||
)));
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_class_scope(&mut self, debug_name: &str) {
|
pub fn push_class_scope(&mut self, debug_name: &str) -> usize {
|
||||||
self.push_scope(Scope::Class(ClassScope::new(
|
self.push_scope(Scope::Class(ClassScope::new(
|
||||||
debug_name,
|
debug_name,
|
||||||
self.current_scope_id.unwrap(),
|
self.current_scope_id.unwrap(),
|
||||||
)));
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_function_scope(&mut self, debug_name: &str) {
|
pub fn push_class_body_scope(&mut self, debug_name: &str) -> usize {
|
||||||
|
self.push_scope(Scope::ClassBody(ClassBodyScope::new(
|
||||||
|
debug_name,
|
||||||
|
self.current_scope_id.unwrap(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_function_scope(&mut self, debug_name: &str) -> usize {
|
||||||
self.push_scope(Scope::Function(FunctionScope::new(
|
self.push_scope(Scope::Function(FunctionScope::new(
|
||||||
debug_name,
|
debug_name,
|
||||||
self.current_scope_id.unwrap(),
|
self.current_scope_id.unwrap(),
|
||||||
)));
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_block_scope(&mut self, debug_name: &str) {
|
pub fn push_block_scope(&mut self, debug_name: &str) -> usize {
|
||||||
self.push_scope(Scope::Block(BlockScope::new(
|
self.push_scope(Scope::Block(BlockScope::new(
|
||||||
debug_name,
|
debug_name,
|
||||||
self.current_scope_id.unwrap(),
|
self.current_scope_id.unwrap(),
|
||||||
)));
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_scope(&mut self) {
|
pub fn pop_scope(&mut self) {
|
||||||
self.current_scope_id = self.current_scope().parent_id();
|
self.current_scope_id = self.scopes[self.current_scope_id.unwrap()].parent_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_scope_id(&self) -> usize {
|
pub fn current_scope_id(&self) -> usize {
|
||||||
self.current_scope_id.unwrap()
|
self.current_scope_id.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_scope(&self) -> &Scope {
|
fn scope(&self, scope_id: usize) -> &Scope {
|
||||||
&self.scopes[self.current_scope_id.unwrap()]
|
&self.scopes[scope_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_scope_mut(&mut self) -> &mut Scope {
|
fn scope_mut(&mut self, scope_id: usize) -> &mut Scope {
|
||||||
&mut self.scopes[self.current_scope_id.unwrap()]
|
&mut self.scopes[scope_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_class_symbol(
|
pub fn get_symbol(&self, scope_id: usize, name: &str) -> Option<Symbol> {
|
||||||
&mut self,
|
match self.scope(scope_id) {
|
||||||
class_symbol: ClassSymbol,
|
Scope::Module(module_scope) => find_in_module_by_name(module_scope, name),
|
||||||
) -> Result<Rc<RefCell<ClassSymbol>>, SymbolInsertError> {
|
Scope::Class(class_scope) => find_in_class_by_name(class_scope, name),
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
Scope::ClassBody(class_body_scope) => {
|
||||||
Scope::Module(module_scope) => {
|
find_in_class_body_by_name(class_body_scope, name)
|
||||||
find_in_module_by_name(module_scope, class_symbol.declared_name())
|
|
||||||
}
|
}
|
||||||
Scope::Class(class_scope) => {
|
Scope::Function(function_scope) => find_in_function_by_name(function_scope, name),
|
||||||
find_in_class_by_name(class_scope, class_symbol.declared_name())
|
Scope::Block(block_scope) => find_in_block_by_name(block_scope, name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_symbol(&mut self, symbol: Symbol) {
|
||||||
|
match symbol {
|
||||||
|
Symbol::Class(class_symbol) => {
|
||||||
|
self.insert_class_symbol(class_symbol);
|
||||||
|
}
|
||||||
|
Symbol::GenericParameter(generic_parameter_symbol) => {
|
||||||
|
self.insert_generic_parameter_symbol(generic_parameter_symbol);
|
||||||
|
}
|
||||||
|
Symbol::Field(field_symbol) => {
|
||||||
|
self.insert_field_symbol(field_symbol);
|
||||||
|
}
|
||||||
|
Symbol::Constructor(constructor_symbol) => {
|
||||||
|
self.insert_constructor_symbol(constructor_symbol);
|
||||||
|
}
|
||||||
|
Symbol::Function(function_symbol) => {
|
||||||
|
self.insert_function_symbol(function_symbol);
|
||||||
|
}
|
||||||
|
Symbol::Parameter(parameter_symbol) => {
|
||||||
|
self.insert_parameter_symbol(parameter_symbol);
|
||||||
|
}
|
||||||
|
Symbol::Variable(variable_symbol) => {
|
||||||
|
self.insert_variable_symbol(variable_symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_class_symbol(&mut self, class_symbol: Rc<ClassSymbol>) {
|
||||||
|
let name = class_symbol.declared_name_owned();
|
||||||
|
match self.scope_mut(class_symbol.scope_id()) {
|
||||||
|
Scope::Module(module_scope) => {
|
||||||
|
module_scope.class_symbols_mut().insert(name, class_symbol);
|
||||||
|
}
|
||||||
|
Scope::ClassBody(class_scope) => {
|
||||||
|
class_scope.class_symbols_mut().insert(name, class_symbol);
|
||||||
}
|
}
|
||||||
_ => panic!("Attempt to insert ClassSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert ClassSymbol in incompatible scope"),
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = class_symbol.declared_name_owned();
|
|
||||||
let as_rc = Rc::new(RefCell::new(class_symbol));
|
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Module(module_scope) => {
|
|
||||||
module_scope.class_symbols_mut().insert(name, as_rc);
|
|
||||||
}
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
class_scope.class_symbols_mut().insert(name, as_rc);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_generic_parameter_symbol(
|
pub fn insert_generic_parameter_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
generic_parameter_symbol: GenericParameterSymbol,
|
generic_parameter_symbol: Rc<GenericParameterSymbol>,
|
||||||
) -> Result<Rc<RefCell<GenericParameterSymbol>>, SymbolInsertError> {
|
) {
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
find_type_symbol_in_class(class_scope, generic_parameter_symbol.declared_name())
|
|
||||||
}
|
|
||||||
_ => panic!("Attempt to insert GenericParameterSymbol in incompatible scope"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
match already_inserted {
|
|
||||||
TypeSymbol::Class(class_symbol) => {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
class_symbol as Rc<RefCell<dyn Symbol>>,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
TypeSymbol::GenericParameter(generic_parameter_symbol) => {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
generic_parameter_symbol as Rc<RefCell<dyn Symbol>>,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = generic_parameter_symbol.declared_name_owned();
|
let name = generic_parameter_symbol.declared_name_owned();
|
||||||
let as_rc = Rc::new(RefCell::new(generic_parameter_symbol));
|
match self.scope_mut(generic_parameter_symbol.scope_id()) {
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Class(class_scope) => {
|
Scope::Class(class_scope) => {
|
||||||
class_scope
|
class_scope
|
||||||
.generic_parameter_symbols_mut()
|
.generic_parameter_symbols_mut()
|
||||||
.insert(name, as_rc);
|
.insert(name, generic_parameter_symbol);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => panic!("Attempt to insert GenericParameterSymbol in incompatible scope"),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_constructor_symbol(
|
pub fn insert_constructor_symbol(&mut self, constructor_symbol: Rc<ConstructorSymbol>) {
|
||||||
&mut self,
|
match self.scope_mut(constructor_symbol.scope_id()) {
|
||||||
constructor_symbol: ConstructorSymbol,
|
Scope::ClassBody(class_scope) => {
|
||||||
) -> Result<Rc<RefCell<ConstructorSymbol>>, SymbolInsertError> {
|
class_scope
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
.constructor_symbol_mut()
|
||||||
Scope::Class(class_scope) => class_scope.constructor_symbol(),
|
.replace(constructor_symbol);
|
||||||
|
}
|
||||||
_ => panic!("Attempt to insert ConstructorSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert ConstructorSymbol in incompatible scope"),
|
||||||
};
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted.clone() as Rc<RefCell<dyn Symbol>>,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let as_rc = Rc::new(RefCell::new(constructor_symbol));
|
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
class_scope.constructor_symbol_mut().replace(as_rc);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_field_symbol(
|
pub fn insert_field_symbol(&mut self, field_symbol: Rc<FieldSymbol>) {
|
||||||
&mut self,
|
let name = field_symbol.declared_name_owned();
|
||||||
field_symbol: FieldSymbol,
|
match self.scope_mut(field_symbol.scope_id()) {
|
||||||
) -> Result<Rc<RefCell<FieldSymbol>>, SymbolInsertError> {
|
Scope::ClassBody(class_scope) => {
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
class_scope.field_symbols_mut().insert(name, field_symbol);
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
find_in_class_by_name(class_scope, field_symbol.declared_name())
|
|
||||||
}
|
}
|
||||||
_ => panic!("Attempt to insert FieldSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert FieldSymbol in incompatible scope"),
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = field_symbol.declared_name_owned();
|
|
||||||
let as_rc = Rc::new(RefCell::new(field_symbol));
|
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
class_scope.field_symbols_mut().insert(name, as_rc);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_function_symbol(
|
pub fn insert_function_symbol(&mut self, function_symbol: Rc<FunctionSymbol>) {
|
||||||
&mut self,
|
let name = function_symbol.declared_name_owned();
|
||||||
function_symbol: FunctionSymbol,
|
match self.scope_mut(function_symbol.scope_id()) {
|
||||||
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolInsertError> {
|
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
|
||||||
Scope::Module(module_scope) => {
|
Scope::Module(module_scope) => {
|
||||||
find_in_module_by_name(module_scope, function_symbol.declared_name())
|
module_scope
|
||||||
|
.function_symbols_mut()
|
||||||
|
.insert(name, function_symbol);
|
||||||
}
|
}
|
||||||
Scope::Class(class_scope) => {
|
Scope::ClassBody(class_scope) => {
|
||||||
find_in_class_by_name(class_scope, function_symbol.declared_name())
|
class_scope
|
||||||
|
.function_symbols_mut()
|
||||||
|
.insert(name, function_symbol);
|
||||||
}
|
}
|
||||||
_ => panic!("Attempt to insert FunctionSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert FunctionSymbol in incompatible scope"),
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = function_symbol.declared_name_owned();
|
|
||||||
let as_rc = Rc::new(RefCell::new(function_symbol));
|
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Module(module_scope) => {
|
|
||||||
module_scope.function_symbols_mut().insert(name, as_rc);
|
|
||||||
}
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
class_scope.function_symbols_mut().insert(name, as_rc);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_parameter_symbol(
|
pub fn insert_parameter_symbol(&mut self, parameter_symbol: Rc<ParameterSymbol>) {
|
||||||
&mut self,
|
|
||||||
parameter_symbol: ParameterSymbol,
|
|
||||||
) -> Result<Rc<RefCell<ParameterSymbol>>, SymbolInsertError> {
|
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
|
||||||
Scope::Function(function_scope) => {
|
|
||||||
find_in_function_by_name(function_scope, parameter_symbol.declared_name())
|
|
||||||
}
|
|
||||||
_ => panic!("Attempt to insert ParameterSymbol in incompatible scope"),
|
|
||||||
};
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = parameter_symbol.declared_name_owned();
|
let name = parameter_symbol.declared_name_owned();
|
||||||
let as_rc = Rc::new(RefCell::new(parameter_symbol));
|
match self.scope_mut(parameter_symbol.scope_id()) {
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Function(function_scope) => {
|
Scope::Function(function_scope) => {
|
||||||
function_scope.parameter_symbols_mut().insert(name, as_rc);
|
function_scope
|
||||||
|
.parameter_symbols_mut()
|
||||||
|
.insert(name, parameter_symbol);
|
||||||
}
|
}
|
||||||
_ => panic!("Attempt to insert ParameterSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert ParameterSymbol in incompatible scope"),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_variable_symbol(
|
pub fn insert_variable_symbol(&mut self, variable_symbol: Rc<VariableSymbol>) {
|
||||||
&mut self,
|
match self.scope_mut(variable_symbol.scope_id()) {
|
||||||
variable_symbol: VariableSymbol,
|
|
||||||
) -> Result<(), SymbolInsertError> {
|
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
|
||||||
Scope::Block(block_scope) => {
|
Scope::Block(block_scope) => {
|
||||||
find_in_block_by_name(block_scope, variable_symbol.declared_name())
|
block_scope
|
||||||
|
.variable_symbols_mut()
|
||||||
|
.insert(variable_symbol.declared_name_owned(), variable_symbol);
|
||||||
}
|
}
|
||||||
_ => panic!("Attempt to insert VariableSymbol in incompatible scope"),
|
_ => panic!("Attempt to insert VariableSymbol in incompatible scope"),
|
||||||
};
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
already_inserted,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
fn find_symbol<S>(
|
||||||
Scope::Block(block_scope) => {
|
&self,
|
||||||
block_scope.variable_symbols_mut().insert(
|
scope_id: usize,
|
||||||
variable_symbol.declared_name_owned(),
|
name: &str,
|
||||||
Rc::new(RefCell::new(variable_symbol)),
|
f: impl Fn(&Scope, &str) -> Option<S>,
|
||||||
);
|
) -> Option<S> {
|
||||||
}
|
let mut maybe_scope = self.scopes.get(scope_id);
|
||||||
_ => unreachable!(),
|
if maybe_scope.is_none() {
|
||||||
|
panic!("Invalid scope_id: {}", scope_id);
|
||||||
}
|
}
|
||||||
Ok(())
|
while let Some(scope) = maybe_scope {
|
||||||
|
let maybe_symbol = f(scope, name);
|
||||||
|
if maybe_symbol.is_some() {
|
||||||
|
return maybe_symbol;
|
||||||
|
} else {
|
||||||
|
maybe_scope = scope.parent_id().and_then(|id| self.scopes.get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_expressible_symbol(
|
pub fn find_expressible_symbol(
|
||||||
@ -353,28 +281,82 @@ impl SymbolTable {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc<RefCell<VariableSymbol>> {
|
pub fn get_class_symbol(&self, scope_id: usize, name: &str) -> Option<&Rc<ClassSymbol>> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::Module(module_scope) => module_scope.class_symbols().get(name),
|
||||||
|
Scope::ClassBody(class_body_scope) => class_body_scope.class_symbols().get(name),
|
||||||
|
_ => panic!("scope_id {} cannot contain classes", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_field_symbol(&self, scope_id: usize, name: &str) -> Option<&FieldSymbol> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::ClassBody(class_body_scope) => {
|
||||||
|
class_body_scope.field_symbols().get(name).map(Rc::as_ref)
|
||||||
|
}
|
||||||
|
_ => panic!("scope_id {} is not a ClassBodyScope", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_constructor_symbol(&self, scope_id: usize) -> Option<&ConstructorSymbol> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::ClassBody(class_body_scope) => {
|
||||||
|
class_body_scope.constructor_symbol().map(Rc::as_ref)
|
||||||
|
}
|
||||||
|
_ => panic!("scope_id {} is not a ClassBodyScope", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_function_symbol(&self, scope_id: usize, name: &str) -> Option<&FunctionSymbol> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::Module(module_scope) => {
|
||||||
|
module_scope.function_symbols().get(name).map(Rc::as_ref)
|
||||||
|
}
|
||||||
|
Scope::ClassBody(class_body_scope) => class_body_scope
|
||||||
|
.function_symbols()
|
||||||
|
.get(name)
|
||||||
|
.map(Rc::as_ref),
|
||||||
|
_ => panic!("scope_id {} cannot contain Functions", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parameter_symbol(&self, scope_id: usize, name: &str) -> Option<&ParameterSymbol> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::Function(function_scope) => {
|
||||||
|
function_scope.parameter_symbols().get(name).map(Rc::as_ref)
|
||||||
|
}
|
||||||
|
_ => panic!("scope_id {} cannot contain Parameters", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parameter_symbol_owned(
|
||||||
|
&self,
|
||||||
|
scope_id: usize,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Rc<ParameterSymbol>> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::Function(function_scope) => {
|
||||||
|
function_scope.parameter_symbols().get(name).cloned()
|
||||||
|
}
|
||||||
|
_ => panic!("scope_id {} cannot contain Parameters", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Option<&VariableSymbol> {
|
||||||
match &self.scopes[scope_id] {
|
match &self.scopes[scope_id] {
|
||||||
Scope::Block(block_scope) => block_scope.variable_symbols().get(name).cloned().unwrap(),
|
Scope::Block(block_scope) => block_scope.variable_symbols().get(name).map(Rc::as_ref),
|
||||||
|
_ => panic!("scope_id {} is not a BlockScope", scope_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_variable_symbol_owned(
|
||||||
|
&self,
|
||||||
|
scope_id: usize,
|
||||||
|
name: &str,
|
||||||
|
) -> Option<Rc<VariableSymbol>> {
|
||||||
|
match self.scope(scope_id) {
|
||||||
|
Scope::Block(block_scope) => block_scope.variable_symbols().get(name).map(Rc::clone),
|
||||||
_ => panic!("scope_id {} is not a BlockScope", scope_id),
|
_ => panic!("scope_id {} is not a BlockScope", scope_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SymbolInsertError {
|
|
||||||
AlreadyDeclared(AlreadyDeclared),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AlreadyDeclared {
|
|
||||||
symbol: Rc<RefCell<dyn Symbol>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AlreadyDeclared {
|
|
||||||
pub fn new(symbol: Rc<RefCell<dyn Symbol>>) -> Self {
|
|
||||||
Self { symbol }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn symbol(&self) -> &Rc<RefCell<dyn Symbol>> {
|
|
||||||
&self.symbol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
||||||
use crate::symbol::type_symbol::TypeSymbol;
|
use crate::symbol::type_symbol::TypeSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -14,9 +12,9 @@ pub enum TypeInfo {
|
|||||||
Integer,
|
Integer,
|
||||||
Double,
|
Double,
|
||||||
String,
|
String,
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<FunctionSymbol>),
|
||||||
ClassInstance(Rc<RefCell<ClassSymbol>>),
|
ClassInstance(Rc<ClassSymbol>),
|
||||||
GenericType(Rc<RefCell<GenericParameterSymbol>>),
|
GenericType(Rc<GenericParameterSymbol>),
|
||||||
Void,
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,16 +27,19 @@ impl Display for TypeInfo {
|
|||||||
TypeInfo::String => write!(f, "String"),
|
TypeInfo::String => write!(f, "String"),
|
||||||
TypeInfo::Function(function_symbol) => {
|
TypeInfo::Function(function_symbol) => {
|
||||||
write!(f, "fn(")?;
|
write!(f, "fn(")?;
|
||||||
for parameter in function_symbol.borrow().parameters() {
|
for (i, parameter) in function_symbol.parameters().iter().enumerate() {
|
||||||
parameter.borrow().type_info().fmt(f)?;
|
parameter.declared_name().fmt(f)?;
|
||||||
|
if i < function_symbol.parameters().len() - 1 {
|
||||||
|
f.write_str(", ")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
TypeInfo::ClassInstance(class_symbol) => {
|
TypeInfo::ClassInstance(class_symbol) => {
|
||||||
write!(f, "{}", class_symbol.borrow().declared_name())
|
write!(f, "{}", class_symbol.declared_name())
|
||||||
}
|
}
|
||||||
TypeInfo::GenericType(generic_parameter_symbol) => {
|
TypeInfo::GenericType(generic_parameter_symbol) => {
|
||||||
write!(f, "{}", generic_parameter_symbol.borrow().declared_name())
|
write!(f, "{}", generic_parameter_symbol.declared_name())
|
||||||
}
|
}
|
||||||
TypeInfo::Void => write!(f, "Void"),
|
TypeInfo::Void => write!(f, "Void"),
|
||||||
}
|
}
|
||||||
@ -58,7 +59,7 @@ impl TypeInfo {
|
|||||||
declared_name: &str,
|
declared_name: &str,
|
||||||
scope_id: usize,
|
scope_id: usize,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
class_context: Option<&Rc<ClassSymbol>>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
match declared_name {
|
match declared_name {
|
||||||
"Any" => Some(TypeInfo::Any),
|
"Any" => Some(TypeInfo::Any),
|
||||||
@ -66,7 +67,7 @@ impl TypeInfo {
|
|||||||
"Double" => Some(TypeInfo::Double),
|
"Double" => Some(TypeInfo::Double),
|
||||||
"String" => Some(TypeInfo::String),
|
"String" => Some(TypeInfo::String),
|
||||||
"Void" => Some(TypeInfo::Void),
|
"Void" => Some(TypeInfo::Void),
|
||||||
"Self" => Some(TypeInfo::ClassInstance(class_context.unwrap().clone())),
|
"Self" => Some(TypeInfo::ClassInstance(class_context.cloned().unwrap())),
|
||||||
_ => match symbol_table.find_type_symbol(scope_id, declared_name) {
|
_ => match symbol_table.find_type_symbol(scope_id, declared_name) {
|
||||||
None => None,
|
None => None,
|
||||||
Some(type_symbol) => match type_symbol {
|
Some(type_symbol) => match type_symbol {
|
||||||
@ -97,14 +98,13 @@ impl TypeInfo {
|
|||||||
TypeInfo::ClassInstance(class_symbol) => {
|
TypeInfo::ClassInstance(class_symbol) => {
|
||||||
match other {
|
match other {
|
||||||
TypeInfo::ClassInstance(other_class_symbol) => {
|
TypeInfo::ClassInstance(other_class_symbol) => {
|
||||||
class_symbol.borrow().declared_name()
|
class_symbol == other_class_symbol // good enough for now
|
||||||
== other_class_symbol.borrow().declared_name() // good enough for now
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeInfo::GenericType(generic_parameter_symbol) => {
|
TypeInfo::GenericType(generic_parameter_symbol) => {
|
||||||
if generic_parameter_symbol.borrow().extends().len() > 0 {
|
if generic_parameter_symbol.extends().len() > 0 {
|
||||||
unimplemented!(
|
unimplemented!(
|
||||||
"Assigning to generic parameter type with extends type uses not yet supported."
|
"Assigning to generic parameter type with extends type uses not yet supported."
|
||||||
);
|
);
|
||||||
|
|||||||
68
dmc-lib/src/types_table.rs
Normal file
68
dmc-lib/src/types_table.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct TypesTable {
|
||||||
|
class_instance_types: HashMap<Rc<ClassSymbol>, TypeInfo>,
|
||||||
|
field_types: HashMap<Rc<FieldSymbol>, TypeInfo>,
|
||||||
|
parameter_types: HashMap<Rc<ParameterSymbol>, TypeInfo>,
|
||||||
|
variable_types: HashMap<Rc<VariableSymbol>, TypeInfo>,
|
||||||
|
function_return_types: HashMap<Rc<FunctionSymbol>, TypeInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypesTable {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
class_instance_types: HashMap::new(),
|
||||||
|
field_types: HashMap::new(),
|
||||||
|
parameter_types: HashMap::new(),
|
||||||
|
variable_types: HashMap::new(),
|
||||||
|
function_return_types: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_instance_types(&self) -> &HashMap<Rc<ClassSymbol>, TypeInfo> {
|
||||||
|
&self.class_instance_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_instance_types_mut(&mut self) -> &mut HashMap<Rc<ClassSymbol>, TypeInfo> {
|
||||||
|
&mut self.class_instance_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_types(&self) -> &HashMap<Rc<FieldSymbol>, TypeInfo> {
|
||||||
|
&self.field_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn field_types_mut(&mut self) -> &mut HashMap<Rc<FieldSymbol>, TypeInfo> {
|
||||||
|
&mut self.field_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameter_types(&self) -> &HashMap<Rc<ParameterSymbol>, TypeInfo> {
|
||||||
|
&self.parameter_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameter_types_mut(&mut self) -> &mut HashMap<Rc<ParameterSymbol>, TypeInfo> {
|
||||||
|
&mut self.parameter_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variable_types(&self) -> &HashMap<Rc<VariableSymbol>, TypeInfo> {
|
||||||
|
&self.variable_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variable_types_mut(&mut self) -> &mut HashMap<Rc<VariableSymbol>, TypeInfo> {
|
||||||
|
&mut self.variable_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function_return_types(&self) -> &HashMap<Rc<FunctionSymbol>, TypeInfo> {
|
||||||
|
&self.function_return_types
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn function_return_types_mut(&mut self) -> &mut HashMap<Rc<FunctionSymbol>, TypeInfo> {
|
||||||
|
&mut self.function_return_types
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ mod e2e_tests {
|
|||||||
use dmc_lib::diagnostic::Diagnostic;
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
|
use dmc_lib::types_table::TypesTable;
|
||||||
use dvm_lib::vm::class::Class;
|
use dvm_lib::vm::class::Class;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::function::Function;
|
use dvm_lib::vm::function::Function;
|
||||||
@ -26,7 +27,7 @@ mod e2e_tests {
|
|||||||
panic!("There were diagnostics.");
|
panic!("There were diagnostics.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_context(input: &str) -> DvmContext {
|
fn prepare_context(input: &str) -> Result<DvmContext, Vec<Diagnostic>> {
|
||||||
let parse_result = parse_compilation_unit(input);
|
let parse_result = parse_compilation_unit(input);
|
||||||
let mut compilation_unit = match parse_result {
|
let mut compilation_unit = match parse_result {
|
||||||
Ok(compilation_unit) => compilation_unit,
|
Ok(compilation_unit) => compilation_unit,
|
||||||
@ -36,29 +37,14 @@ mod e2e_tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
let mut types_table = TypesTable::new();
|
||||||
|
|
||||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
compilation_unit.init_scopes(&mut symbol_table);
|
||||||
Ok(_) => {}
|
compilation_unit.gather_symbols_into(&mut symbol_table)?;
|
||||||
Err(diagnostics) => {
|
compilation_unit.check_names(&mut symbol_table)?;
|
||||||
report_diagnostics(&diagnostics);
|
compilation_unit.type_check(&symbol_table, &mut types_table)?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.check_name_usages(&symbol_table) {
|
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table, &types_table);
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
report_diagnostics(&diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
report_diagnostics(&diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (ir_classes, mut ir_functions) = compilation_unit.to_ir(&symbol_table);
|
|
||||||
|
|
||||||
let mut functions: Vec<Function> = vec![];
|
let mut functions: Vec<Function> = vec![];
|
||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
@ -95,7 +81,7 @@ mod e2e_tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dvm_context
|
Ok(dvm_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_result(
|
fn get_result(
|
||||||
@ -116,7 +102,10 @@ mod e2e_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
fn assert_result(input: &str, function_name: &str, arguments: &[Value], expected_value: Value) {
|
||||||
let context = prepare_context(input);
|
let context = match prepare_context(input) {
|
||||||
|
Ok(context) => context,
|
||||||
|
Err(diagnostics) => report_diagnostics(&diagnostics),
|
||||||
|
};
|
||||||
match get_result(&context, function_name, arguments) {
|
match get_result(&context, function_name, arguments) {
|
||||||
None => panic!("Call returned no value"),
|
None => panic!("Call returned no value"),
|
||||||
Some(result_value) => {
|
Some(result_value) => {
|
||||||
@ -215,7 +204,7 @@ mod e2e_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn two_classes() {
|
fn two_classes() -> Result<(), Vec<Diagnostic>> {
|
||||||
let context = prepare_context(
|
let context = prepare_context(
|
||||||
"
|
"
|
||||||
class Foo
|
class Foo
|
||||||
@ -239,7 +228,7 @@ mod e2e_tests {
|
|||||||
Foo(n)
|
Foo(n)
|
||||||
end
|
end
|
||||||
",
|
",
|
||||||
);
|
)?;
|
||||||
let result = get_result(&context, "foo", &[Value::Int(42)]);
|
let result = get_result(&context, "foo", &[Value::Int(42)]);
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
@ -247,6 +236,7 @@ mod e2e_tests {
|
|||||||
let o = value.unwrap_object().borrow();
|
let o = value.unwrap_object().borrow();
|
||||||
assert_eq!(o.fields().len(), 1);
|
assert_eq!(o.fields().len(), 1);
|
||||||
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -266,7 +256,7 @@ mod e2e_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assign_field() {
|
fn assign_field() -> Result<(), Vec<Diagnostic>> {
|
||||||
let context = prepare_context(
|
let context = prepare_context(
|
||||||
"
|
"
|
||||||
class Foo
|
class Foo
|
||||||
@ -281,7 +271,7 @@ mod e2e_tests {
|
|||||||
Foo(42)
|
Foo(42)
|
||||||
end
|
end
|
||||||
",
|
",
|
||||||
);
|
)?;
|
||||||
let result = get_result(&context, "foo", &vec![]);
|
let result = get_result(&context, "foo", &vec![]);
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
@ -289,10 +279,11 @@ mod e2e_tests {
|
|||||||
let o = value.unwrap_object().borrow();
|
let o = value.unwrap_object().borrow();
|
||||||
assert_eq!(o.fields().len(), 1);
|
assert_eq!(o.fields().len(), 1);
|
||||||
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn see_what_happens() {
|
fn see_what_happens() -> Result<(), Vec<Diagnostic>> {
|
||||||
let context = prepare_context(
|
let context = prepare_context(
|
||||||
"
|
"
|
||||||
class Foo<T>
|
class Foo<T>
|
||||||
@ -306,7 +297,7 @@ mod e2e_tests {
|
|||||||
Foo(42)
|
Foo(42)
|
||||||
end
|
end
|
||||||
",
|
",
|
||||||
);
|
)?;
|
||||||
let result = get_result(&context, "main", &vec![]);
|
let result = get_result(&context, "main", &vec![]);
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
@ -314,49 +305,6 @@ mod e2e_tests {
|
|||||||
let o = value.unwrap_object().borrow();
|
let o = value.unwrap_object().borrow();
|
||||||
assert_eq!(o.fields().len(), 1);
|
assert_eq!(o.fields().len(), 1);
|
||||||
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
||||||
}
|
Ok(())
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod diagnostic_tests {
|
|
||||||
use dmc_lib::diagnostic::Diagnostic;
|
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
|
||||||
|
|
||||||
fn get_diagnostics(input: &str) -> Vec<Diagnostic> {
|
|
||||||
let parse_result = parse_compilation_unit(input);
|
|
||||||
let mut compilation_unit = match parse_result {
|
|
||||||
Ok(compilation_unit) => compilation_unit,
|
|
||||||
Err(diagnostics) => {
|
|
||||||
return diagnostics;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
|
||||||
|
|
||||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
return diagnostics;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.check_name_usages(&symbol_table) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(diagnostics) => {
|
|
||||||
return diagnostics;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match compilation_unit.type_check(&symbol_table) {
|
|
||||||
Ok(_) => vec![],
|
|
||||||
Err(diagnostics) => diagnostics,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn wrong_return_type() {
|
|
||||||
let diagnostics = get_diagnostics("fn main() -> String 42 end");
|
|
||||||
assert_eq!(diagnostics.len(), 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user