Name analysis for classes and affected things.
This commit is contained in:
parent
efecd6b9c8
commit
75dcca0002
@ -133,8 +133,12 @@ fn compile_expression(
|
||||
"__repl",
|
||||
SourceRange::new(0, 0),
|
||||
false,
|
||||
expression.type_info().clone(), // dubious
|
||||
)));
|
||||
|
||||
fake_function_symbol
|
||||
.borrow_mut()
|
||||
.set_return_type_info(expression.type_info().clone());
|
||||
|
||||
let mut ir_function = IrFunction::new(
|
||||
fake_function_symbol,
|
||||
&[],
|
||||
|
||||
@ -2,7 +2,8 @@ use crate::ast::field::Field;
|
||||
use crate::ast::function::Function;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Class {
|
||||
@ -32,16 +33,142 @@ impl Class {
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// 1. insert class symbol
|
||||
// 2. gather fields
|
||||
// 3. gather functions
|
||||
todo!()
|
||||
let to_insert = ClassSymbol::new(
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
false,
|
||||
);
|
||||
|
||||
symbol_table
|
||||
.insert_class_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(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
]
|
||||
}
|
||||
})?;
|
||||
|
||||
// 2. push scope
|
||||
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
||||
|
||||
// 3. gather fields
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.gather_declared_names(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if !fields_diagnostics.is_empty() {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
// 4. gather functions
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.gather_declared_names(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if !functions_diagnostics.is_empty() {
|
||||
return Err(functions_diagnostics);
|
||||
}
|
||||
|
||||
// 5. pop scope
|
||||
symbol_table.pop_scope();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
todo!()
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
if !fields_diagnostics.is_empty() {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
.map(|function| function.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if functions_diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(functions_diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::parser::parse_compilation_unit;
|
||||
|
||||
#[test]
|
||||
fn name_analysis_no_diagnostics() {
|
||||
let parse_result = parse_compilation_unit(
|
||||
"
|
||||
class Foo
|
||||
mut bar = 42
|
||||
|
||||
fn baz() -> Int
|
||||
bar
|
||||
end
|
||||
end
|
||||
|
||||
class Qux
|
||||
fn foo() -> Foo
|
||||
Foo()
|
||||
end
|
||||
end
|
||||
",
|
||||
);
|
||||
|
||||
let mut compilation_unit = match parse_result {
|
||||
Ok(compilation_unit) => compilation_unit,
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
};
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
match compilation_unit.gather_declared_names(&mut symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
match compilation_unit.check_name_usages(&symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(diagnostics) => {
|
||||
panic!("{:?}", diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,12 +4,15 @@ use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct ExternFunction {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
return_type: TypeUse,
|
||||
function_symbol: Option<Rc<RefCell<FunctionSymbol>>>,
|
||||
}
|
||||
|
||||
impl ExternFunction {
|
||||
@ -24,6 +27,7 @@ impl ExternFunction {
|
||||
declared_name_source_range,
|
||||
parameters,
|
||||
return_type,
|
||||
function_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +45,6 @@ impl ExternFunction {
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
true,
|
||||
self.return_type.to_type_info(),
|
||||
));
|
||||
|
||||
let function_symbol = match insert_result {
|
||||
@ -82,6 +85,16 @@ impl ExternFunction {
|
||||
.borrow_mut()
|
||||
.set_parameters(parameter_symbols);
|
||||
|
||||
self.function_symbol = Some(function_symbol);
|
||||
|
||||
// handle return type
|
||||
match self.return_type.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
symbol_table.pop_scope(); // function scope
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
@ -92,14 +105,29 @@ impl ExternFunction {
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let diagnostics: Vec<Diagnostic> = self
|
||||
let mut diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|parameter| parameter.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
match self.return_type.check_name_usages(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut return_type_diagnostics) => {
|
||||
diagnostics.append(&mut return_type_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
// set return type info on symbol now that its available
|
||||
self.function_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(self.return_type.to_type_info());
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::type_use::TypeUse;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Field {
|
||||
@ -30,4 +33,51 @@ impl Field {
|
||||
initializer: initializer.map(Box::new),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// 1. insert field symbol
|
||||
let to_insert =
|
||||
FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone());
|
||||
|
||||
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(),
|
||||
)]
|
||||
}
|
||||
})?;
|
||||
|
||||
// 2. gather initializer, if present
|
||||
if let Some(initializer) = &mut self.initializer {
|
||||
initializer.gather_declared_names(symbol_table)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
if let Some(type_use) = &mut self.declared_type {
|
||||
type_use.check_name_usages(symbol_table)?;
|
||||
}
|
||||
|
||||
// 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(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,15 +58,15 @@ impl Function {
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
return Err(diagnostics);
|
||||
}
|
||||
|
||||
// insert function symbol
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
self.declared_name(),
|
||||
self.declared_name_source_range.clone(),
|
||||
false,
|
||||
self.return_type
|
||||
.as_ref()
|
||||
.map(|return_type| return_type.to_type_info())
|
||||
.unwrap_or(TypeInfo::Void),
|
||||
));
|
||||
|
||||
// get function symbol if successful
|
||||
@ -109,6 +109,16 @@ impl Function {
|
||||
.borrow_mut()
|
||||
.set_parameters(parameter_symbols);
|
||||
|
||||
// return type
|
||||
if let Some(type_use) = &mut self.return_type {
|
||||
match type_use.gather_declared_names(symbol_table) {
|
||||
Ok(_) => {}
|
||||
Err(mut type_use_diagnostics) => {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
symbol_table.push_block_scope(&format!("main_block_scope({})", self.declared_name));
|
||||
for statement in &mut self.statements {
|
||||
match statement.gather_declared_names(symbol_table) {
|
||||
@ -142,6 +152,28 @@ impl Function {
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// return type
|
||||
if let Some(type_use) = &mut self.return_type {
|
||||
match type_use.check_name_usages(symbol_table) {
|
||||
Ok(_) => {
|
||||
// set return type info on function symbol
|
||||
self.function_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(type_use.to_type_info());
|
||||
}
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
// statements
|
||||
for statement in &mut self.statements {
|
||||
match statement.check_name_usages(symbol_table) {
|
||||
|
||||
@ -32,6 +32,7 @@ impl Parameter {
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
|
||||
// insert parameter symbol
|
||||
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
|
||||
&self.declared_name,
|
||||
self.declared_name_source_range.clone(),
|
||||
@ -40,26 +41,32 @@ impl Parameter {
|
||||
match insert_result {
|
||||
Ok(parameter_symbol) => {
|
||||
self.parameter_symbol = Some(parameter_symbol.clone());
|
||||
Ok(parameter_symbol)
|
||||
}
|
||||
Err(symbol_insert_error) => match symbol_insert_error {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new(
|
||||
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(),
|
||||
)]),
|
||||
},
|
||||
)])
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(
|
||||
&mut self,
|
||||
_symbol_table: &SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
Ok(()) // no-op for now
|
||||
// type use
|
||||
self.type_use.gather_declared_names(symbol_table)?;
|
||||
|
||||
Ok(self.parameter_symbol.clone().unwrap())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.type_use.check_name_usages(symbol_table)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::type_symbol::{PrimitiveTypeSymbol, TypeSymbol};
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::type_info::TypeInfo;
|
||||
|
||||
pub struct TypeUse {
|
||||
declared_name: String,
|
||||
declared_name_source_range: SourceRange,
|
||||
scope_id: Option<usize>,
|
||||
type_symbol: Option<TypeSymbol>,
|
||||
}
|
||||
|
||||
impl TypeUse {
|
||||
@ -11,6 +16,8 @@ impl TypeUse {
|
||||
Self {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
scope_id: None,
|
||||
type_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +25,47 @@ impl TypeUse {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut 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>> {
|
||||
let maybe_type_symbol =
|
||||
symbol_table.find_type_symbol(self.scope_id.unwrap(), &self.declared_name);
|
||||
if let Some(type_symbol) = maybe_type_symbol {
|
||||
self.type_symbol = Some(type_symbol);
|
||||
Ok(())
|
||||
} else if let Some(primitive_type_symbol) =
|
||||
PrimitiveTypeSymbol::try_from_declared_name(self.declared_name())
|
||||
{
|
||||
self.type_symbol = Some(TypeSymbol::Primitive(primitive_type_symbol));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vec![
|
||||
Diagnostic::new(
|
||||
&format!("Unable to resolve symbol {}", self.declared_name),
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_type_info(&self) -> TypeInfo {
|
||||
TypeInfo::from_declared_name(self.declared_name())
|
||||
match self.type_symbol.as_ref().unwrap() {
|
||||
TypeSymbol::Class(class_symbol) => TypeInfo::Class(class_symbol.clone()),
|
||||
TypeSymbol::Primitive(primitive_type) => match primitive_type {
|
||||
PrimitiveTypeSymbol::Any => TypeInfo::Any,
|
||||
PrimitiveTypeSymbol::Int => TypeInfo::Integer,
|
||||
PrimitiveTypeSymbol::Double => TypeInfo::Double,
|
||||
PrimitiveTypeSymbol::String => TypeInfo::String,
|
||||
PrimitiveTypeSymbol::Void => TypeInfo::Void,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ pub struct FunctionSymbol {
|
||||
declared_name_source_range: SourceRange,
|
||||
is_extern: bool,
|
||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||
return_type: TypeInfo,
|
||||
return_type: Option<TypeInfo>,
|
||||
}
|
||||
|
||||
impl FunctionSymbol {
|
||||
@ -18,27 +18,16 @@ impl FunctionSymbol {
|
||||
declared_name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
is_extern: bool,
|
||||
return_type: TypeInfo,
|
||||
) -> Self {
|
||||
Self {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
is_extern,
|
||||
parameters: None,
|
||||
return_type,
|
||||
return_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(note = "use declared_name")]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
#[deprecated(note = "use declared_name_owned")]
|
||||
pub fn name_owned(&self) -> Rc<str> {
|
||||
self.declared_name.clone()
|
||||
}
|
||||
|
||||
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
||||
self.parameters = Some(parameters);
|
||||
}
|
||||
@ -47,8 +36,12 @@ impl FunctionSymbol {
|
||||
self.parameters.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn set_return_type_info(&mut self, return_type: TypeInfo) {
|
||||
self.return_type = Some(return_type);
|
||||
}
|
||||
|
||||
pub fn return_type_info(&self) -> &TypeInfo {
|
||||
&self.return_type
|
||||
self.return_type.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn is_extern(&self) -> bool {
|
||||
|
||||
@ -6,6 +6,7 @@ pub mod expressible_symbol;
|
||||
pub mod field_symbol;
|
||||
pub mod function_symbol;
|
||||
pub mod parameter_symbol;
|
||||
pub mod type_symbol;
|
||||
pub mod variable_symbol;
|
||||
|
||||
pub trait Symbol {
|
||||
|
||||
29
dmc-lib/src/symbol/type_symbol.rs
Normal file
29
dmc-lib/src/symbol/type_symbol.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum TypeSymbol {
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Primitive(PrimitiveTypeSymbol),
|
||||
}
|
||||
|
||||
pub enum PrimitiveTypeSymbol {
|
||||
Any,
|
||||
Int,
|
||||
Double,
|
||||
String,
|
||||
Void,
|
||||
}
|
||||
|
||||
impl PrimitiveTypeSymbol {
|
||||
pub fn try_from_declared_name(declared_name: &str) -> Option<PrimitiveTypeSymbol> {
|
||||
match declared_name {
|
||||
"Any" => Some(PrimitiveTypeSymbol::Any),
|
||||
"Int" => Some(PrimitiveTypeSymbol::Int),
|
||||
"Double" => Some(PrimitiveTypeSymbol::Double),
|
||||
"String" => Some(PrimitiveTypeSymbol::String),
|
||||
"Void" => Some(PrimitiveTypeSymbol::Void),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ use crate::scope::function_scope::FunctionScope;
|
||||
use crate::scope::module_scope::ModuleScope;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::type_symbol::TypeSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -134,3 +135,25 @@ pub fn find_expressible_symbol(scope: &Scope, name: &str) -> Option<ExpressibleS
|
||||
Scope::Block(block_scope) => find_expressible_in_block_by_name(block_scope, name),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option<TypeSymbol> {
|
||||
module_scope
|
||||
.class_symbols()
|
||||
.get(name)
|
||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||
}
|
||||
|
||||
fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
||||
class_scope
|
||||
.class_symbols()
|
||||
.get(name)
|
||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||
}
|
||||
|
||||
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
||||
match scope {
|
||||
Scope::Module(module_scope) => find_type_symbol_in_module(module_scope, name),
|
||||
Scope::Class(class_scope) => find_type_symbol_in_class(class_scope, name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,13 +6,16 @@ use crate::scope::class_scope::ClassScope;
|
||||
use crate::scope::function_scope::FunctionScope;
|
||||
use crate::scope::module_scope::ModuleScope;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::symbol::type_symbol::TypeSymbol;
|
||||
use crate::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::symbol_table::helpers::{
|
||||
find_expressible_symbol, find_in_block_by_name, find_in_class_by_name,
|
||||
find_in_function_by_name, find_in_module_by_name,
|
||||
find_in_function_by_name, find_in_module_by_name, find_type_symbol,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
@ -84,6 +87,72 @@ impl SymbolTable {
|
||||
&mut self.scopes[self.current_scope_id.unwrap()]
|
||||
}
|
||||
|
||||
pub fn insert_class_symbol(
|
||||
&mut self,
|
||||
class_symbol: ClassSymbol,
|
||||
) -> Result<Rc<RefCell<ClassSymbol>>, SymbolInsertError> {
|
||||
let maybe_already_inserted = match self.current_scope() {
|
||||
Scope::Module(module_scope) => {
|
||||
find_in_module_by_name(module_scope, class_symbol.declared_name())
|
||||
}
|
||||
Scope::Class(class_scope) => {
|
||||
find_in_class_by_name(class_scope, class_symbol.declared_name())
|
||||
}
|
||||
_ => 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_field_symbol(
|
||||
&mut self,
|
||||
field_symbol: FieldSymbol,
|
||||
) -> Result<Rc<RefCell<FieldSymbol>>, SymbolInsertError> {
|
||||
let maybe_already_inserted = match self.current_scope() {
|
||||
Scope::Class(class_scope) => {
|
||||
find_in_class_by_name(class_scope, field_symbol.declared_name())
|
||||
}
|
||||
_ => 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(
|
||||
&mut self,
|
||||
function_symbol: FunctionSymbol,
|
||||
@ -198,6 +267,22 @@ impl SymbolTable {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_type_symbol(&self, scope_id: usize, name: &str) -> Option<TypeSymbol> {
|
||||
let mut maybe_scope = self.scopes.get(scope_id);
|
||||
if maybe_scope.is_none() {
|
||||
panic!("Invalid scope_id: {}", scope_id);
|
||||
}
|
||||
while let Some(scope) = maybe_scope {
|
||||
let maybe_type_symbol = find_type_symbol(scope, name);
|
||||
if maybe_type_symbol.is_some() {
|
||||
return maybe_type_symbol;
|
||||
} else {
|
||||
maybe_scope = scope.parent_id().map(|id| &self.scopes[id]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_variable_symbol(&self, scope_id: usize, name: &str) -> Rc<RefCell<VariableSymbol>> {
|
||||
match &self.scopes[scope_id] {
|
||||
Scope::Block(block_scope) => block_scope.variable_symbols().get(name).cloned().unwrap(),
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::class_symbol::ClassSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -10,6 +12,7 @@ pub enum TypeInfo {
|
||||
Double,
|
||||
String,
|
||||
Function(Rc<RefCell<FunctionSymbol>>),
|
||||
Class(Rc<RefCell<ClassSymbol>>),
|
||||
Void,
|
||||
}
|
||||
|
||||
@ -27,6 +30,9 @@ impl Display for TypeInfo {
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
TypeInfo::Class(class_symbol) => {
|
||||
write!(f, "{}", class_symbol.borrow().declared_name())
|
||||
}
|
||||
TypeInfo::Void => write!(f, "Void"),
|
||||
}
|
||||
}
|
||||
@ -34,6 +40,7 @@ impl Display for TypeInfo {
|
||||
|
||||
impl TypeInfo {
|
||||
// This is very naive but works for now
|
||||
#[deprecated]
|
||||
pub fn from_declared_name(declared_name: &str) -> Self {
|
||||
match declared_name {
|
||||
"Any" => TypeInfo::Any,
|
||||
@ -60,6 +67,15 @@ impl TypeInfo {
|
||||
TypeInfo::Function(_) => {
|
||||
unimplemented!("Type matching on Functions not yet supported.")
|
||||
}
|
||||
TypeInfo::Class(class_symbol) => {
|
||||
match other {
|
||||
TypeInfo::Class(other_class_symbol) => {
|
||||
class_symbol.borrow().declared_name()
|
||||
== other_class_symbol.borrow().declared_name() // good enough for now
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
TypeInfo::Void => {
|
||||
matches!(other, TypeInfo::Void)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user