Add ctors, most name-analysis for classes/fields/constructors.
This commit is contained in:
parent
75dcca0002
commit
ad821ce6a7
@ -1,3 +1,4 @@
|
||||
use crate::ast::constructor::Constructor;
|
||||
use crate::ast::field::Field;
|
||||
use crate::ast::function::Function;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
@ -9,6 +10,7 @@ use std::rc::Rc;
|
||||
pub struct Class {
|
||||
declared_name: Rc<str>,
|
||||
declared_name_source_range: SourceRange,
|
||||
constructor: Option<Constructor>,
|
||||
fields: Vec<Field>,
|
||||
functions: Vec<Function>,
|
||||
}
|
||||
@ -17,12 +19,14 @@ impl Class {
|
||||
pub fn new(
|
||||
declared_name: &str,
|
||||
declared_name_source_range: SourceRange,
|
||||
constructor: Option<Constructor>,
|
||||
fields: Vec<Field>,
|
||||
functions: Vec<Function>,
|
||||
) -> Self {
|
||||
Class {
|
||||
declared_name: declared_name.into(),
|
||||
declared_name_source_range,
|
||||
constructor,
|
||||
fields,
|
||||
functions,
|
||||
}
|
||||
@ -73,7 +77,12 @@ impl Class {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
// 4. gather functions
|
||||
// 4. gather constructor
|
||||
if let Some(constructor) = &mut self.constructor {
|
||||
constructor.gather_declared_names(symbol_table)?;
|
||||
}
|
||||
|
||||
// 5. gather functions
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
@ -86,13 +95,18 @@ impl Class {
|
||||
return Err(functions_diagnostics);
|
||||
}
|
||||
|
||||
// 5. pop scope
|
||||
// 6. pop scope
|
||||
symbol_table.pop_scope();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
self.constructor
|
||||
.as_mut()
|
||||
.map(|constructor| constructor.check_name_usages(symbol_table))
|
||||
.transpose()?;
|
||||
|
||||
let fields_diagnostics: Vec<Diagnostic> = self
|
||||
.fields
|
||||
.iter_mut()
|
||||
@ -104,6 +118,10 @@ impl Class {
|
||||
return Err(fields_diagnostics);
|
||||
}
|
||||
|
||||
if let Some(constructor) = &mut self.constructor {
|
||||
constructor.check_name_usages(symbol_table)?;
|
||||
}
|
||||
|
||||
let functions_diagnostics: Vec<Diagnostic> = self
|
||||
.functions
|
||||
.iter_mut()
|
||||
@ -120,7 +138,26 @@ impl Class {
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
todo!()
|
||||
// We need to determine if fields are initialized or not (the latter is an error).
|
||||
// First phase: check all fields, then check constructor, leaving pending those things that
|
||||
// are fields <- initialized by constructor. Then circle back to fields and check all are
|
||||
// initialized
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
self.fields
|
||||
.iter_mut()
|
||||
.map(|field| field.type_check(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.for_each(|diagnostic| diagnostics.push(diagnostic));
|
||||
|
||||
// todo check constructor and functions and re-check fields
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +171,10 @@ mod tests {
|
||||
let parse_result = parse_compilation_unit(
|
||||
"
|
||||
class Foo
|
||||
mut bar = 42
|
||||
mut bar: Int
|
||||
|
||||
ctor(_bar: Int)
|
||||
end
|
||||
|
||||
fn baz() -> Int
|
||||
bar
|
||||
@ -143,7 +183,7 @@ mod tests {
|
||||
|
||||
class Qux
|
||||
fn foo() -> Foo
|
||||
Foo()
|
||||
Foo(42)
|
||||
end
|
||||
end
|
||||
",
|
||||
|
||||
127
dmc-lib/src/ast/constructor.rs
Normal file
127
dmc-lib/src/ast/constructor.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use crate::ast::parameter::Parameter;
|
||||
use crate::ast::statement::Statement;
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Constructor {
|
||||
is_public: bool,
|
||||
ctor_keyword_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
statements: Vec<Statement>,
|
||||
}
|
||||
|
||||
impl Constructor {
|
||||
pub fn new(
|
||||
is_public: bool,
|
||||
ctor_keyword_source_range: SourceRange,
|
||||
parameters: Vec<Parameter>,
|
||||
statements: Vec<Statement>,
|
||||
) -> Self {
|
||||
Self {
|
||||
is_public,
|
||||
ctor_keyword_source_range,
|
||||
parameters,
|
||||
statements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_declared_names(
|
||||
&mut self,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
// insert constructor symbol
|
||||
let to_insert = ConstructorSymbol::new(self.ctor_keyword_source_range.clone(), false);
|
||||
let constructor_symbol =
|
||||
symbol_table
|
||||
.insert_constructor_symbol(to_insert)
|
||||
.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");
|
||||
|
||||
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(())
|
||||
} else {
|
||||
Err(statements_diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let parameters_diagnostics: Vec<Diagnostic> = self
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.map(|param| param.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if !parameters_diagnostics.is_empty() {
|
||||
return Err(parameters_diagnostics);
|
||||
}
|
||||
|
||||
let statements_diagnostics: Vec<Diagnostic> = self
|
||||
.statements
|
||||
.iter_mut()
|
||||
.map(|statement| statement.check_name_usages(symbol_table))
|
||||
.filter_map(Result::err)
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
if statements_diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(statements_diagnostics)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ use crate::diagnostic::Diagnostic;
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Field {
|
||||
@ -13,6 +14,7 @@ pub struct Field {
|
||||
is_mut: bool,
|
||||
declared_type: Option<Box<TypeUse>>,
|
||||
initializer: Option<Box<Expression>>,
|
||||
field_symbol: Option<Rc<RefCell<FieldSymbol>>>,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
@ -31,6 +33,7 @@ impl Field {
|
||||
is_mut,
|
||||
declared_type: declared_type.map(Box::new),
|
||||
initializer: initializer.map(Box::new),
|
||||
field_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +45,7 @@ impl Field {
|
||||
let to_insert =
|
||||
FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone());
|
||||
|
||||
symbol_table
|
||||
let field_symbol = symbol_table
|
||||
.insert_field_symbol(to_insert)
|
||||
.map_err(|e| match e {
|
||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||
@ -57,7 +60,14 @@ impl Field {
|
||||
}
|
||||
})?;
|
||||
|
||||
// 2. gather initializer, if present
|
||||
// save for later
|
||||
self.field_symbol = Some(field_symbol);
|
||||
|
||||
// 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)?;
|
||||
}
|
||||
@ -80,4 +90,83 @@ impl Field {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
if let Some(type_use) = &mut self.declared_type {
|
||||
if let Some(mut type_use_diagnostics) = type_use.type_check(symbol_table).err() {
|
||||
diagnostics.append(&mut type_use_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(initializer) = &mut self.initializer {
|
||||
if let Some(mut initializer_diagnostics) = initializer.type_check(symbol_table).err() {
|
||||
diagnostics.append(&mut initializer_diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
return Err(diagnostics);
|
||||
}
|
||||
|
||||
// Now check that types are assignable, and update field symbol's type info
|
||||
let field_type_info =
|
||||
match self.declared_type.as_ref() {
|
||||
Some(type_use) => {
|
||||
match self.initializer.as_ref() {
|
||||
Some(initializer) => {
|
||||
let initializer_type_info = initializer.type_info();
|
||||
let declared_type_info = type_use.to_type_info();
|
||||
if declared_type_info.is_assignable_from(initializer_type_info) {
|
||||
declared_type_info
|
||||
} else {
|
||||
return Err(vec![
|
||||
Diagnostic::new(
|
||||
&format!(
|
||||
"Mismatched types: {} is not assignable to {}",
|
||||
initializer_type_info, declared_type_info
|
||||
),
|
||||
initializer.source_range().start(),
|
||||
initializer.source_range().end(),
|
||||
)
|
||||
.with_reporter(file!(), line!()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// easy: the declared type
|
||||
type_use.to_type_info()
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// type is the initializer
|
||||
match self.initializer.as_ref() {
|
||||
Some(initializer) => initializer.type_info().clone(),
|
||||
None => {
|
||||
// this is an error
|
||||
return Err(vec![Diagnostic::new(
|
||||
"Field must have either a declared type or initializer, or both.",
|
||||
self.declared_name_source_range.start(),
|
||||
self.declared_name_source_range.end(),
|
||||
).with_reporter(file!(), line!())]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// update field symbol's type info
|
||||
self.field_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_type_info(field_type_info);
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,9 +169,11 @@ impl Function {
|
||||
}
|
||||
} 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
|
||||
);
|
||||
self.function_symbol
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type_info(TypeInfo::Void);
|
||||
}
|
||||
|
||||
// statements
|
||||
|
||||
@ -2,6 +2,7 @@ pub mod add_expression;
|
||||
pub mod call;
|
||||
pub mod class;
|
||||
pub mod compilation_unit;
|
||||
pub mod constructor;
|
||||
pub mod double_literal;
|
||||
pub mod expression;
|
||||
pub mod expression_statement;
|
||||
|
||||
@ -56,6 +56,10 @@ impl TypeUse {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||
Ok(()) // no-op, for now
|
||||
}
|
||||
|
||||
pub fn to_type_info(&self) -> TypeInfo {
|
||||
match self.type_symbol.as_ref().unwrap() {
|
||||
TypeSymbol::Class(class_symbol) => TypeInfo::Class(class_symbol.clone()),
|
||||
|
||||
@ -136,6 +136,7 @@ impl<'a> Lexer<'a> {
|
||||
"self" => TokenKind::SelfKw,
|
||||
"pub" => TokenKind::Public,
|
||||
"mut" => TokenKind::Mut,
|
||||
"ctor" => TokenKind::Ctor,
|
||||
_ => TokenKind::Identifier,
|
||||
};
|
||||
Token::new(self.position, self.position + prefix.len(), token_kind)
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::ast::add_expression::AddExpression;
|
||||
use crate::ast::call::Call;
|
||||
use crate::ast::class::Class;
|
||||
use crate::ast::compilation_unit::CompilationUnit;
|
||||
use crate::ast::constructor::Constructor;
|
||||
use crate::ast::double_literal::DoubleLiteral;
|
||||
use crate::ast::expression::Expression;
|
||||
use crate::ast::expression_statement::ExpressionStatement;
|
||||
@ -49,6 +50,12 @@ macro_rules! matches_expression_first {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! matches_statement_first {
|
||||
( $token_kind : expr ) => {
|
||||
matches!($token_kind, TokenKind::Let) || matches_expression_first!($token_kind)
|
||||
};
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
input: &'a str,
|
||||
lexer: Lexer<'a>,
|
||||
@ -382,12 +389,17 @@ impl<'a> Parser<'a> {
|
||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||
let mut fields = vec![];
|
||||
let mut functions = vec![];
|
||||
let mut maybe_constructor: Option<Constructor> = None;
|
||||
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
while self.current.is_some() && !self.peek_current(TokenKind::End) {
|
||||
match self.get_current().kind() {
|
||||
TokenKind::Public => match self.public_class_member(&mut fields, &mut functions) {
|
||||
TokenKind::Public => match self.public_class_member(
|
||||
&mut fields,
|
||||
&mut functions,
|
||||
&mut maybe_constructor,
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(mut member_diagnostics) => diagnostics.append(&mut member_diagnostics),
|
||||
},
|
||||
@ -399,6 +411,12 @@ impl<'a> Parser<'a> {
|
||||
Ok(function) => functions.push(function),
|
||||
Err(mut function_diagnostics) => diagnostics.append(&mut function_diagnostics),
|
||||
},
|
||||
TokenKind::Ctor => match self.constructor() {
|
||||
Ok(constructor) => {
|
||||
maybe_constructor = Some(constructor);
|
||||
}
|
||||
Err(mut ctor_diagnostics) => diagnostics.append(&mut ctor_diagnostics),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@ -409,6 +427,7 @@ impl<'a> Parser<'a> {
|
||||
Ok(Class::new(
|
||||
self.token_text(&identifier_token),
|
||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||
maybe_constructor,
|
||||
fields,
|
||||
functions,
|
||||
))
|
||||
@ -469,26 +488,29 @@ impl<'a> Parser<'a> {
|
||||
&mut self,
|
||||
fields: &mut Vec<Field>,
|
||||
functions: &mut Vec<Function>,
|
||||
maybe_ctor: &mut Option<Constructor>,
|
||||
) -> Result<(), Vec<Diagnostic>> {
|
||||
if self.lookahead.is_some() {
|
||||
if matches!(
|
||||
self.lookahead.as_ref().unwrap().kind(),
|
||||
TokenKind::Mut | TokenKind::Identifier
|
||||
) {
|
||||
fields.push(self.field()?);
|
||||
} else if matches!(self.lookahead.as_ref().unwrap().kind(), TokenKind::Fn) {
|
||||
functions.push(self.function()?);
|
||||
} else {
|
||||
let lookahead = self.lookahead.as_ref().unwrap();
|
||||
return Err(vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Expected any of {:?}; found {:?}",
|
||||
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
|
||||
lookahead.kind()
|
||||
),
|
||||
lookahead.start(),
|
||||
lookahead.end(),
|
||||
)]);
|
||||
match self.lookahead.as_ref().unwrap().kind() {
|
||||
TokenKind::Mut | TokenKind::Identifier => {
|
||||
fields.push(self.field()?);
|
||||
}
|
||||
TokenKind::Fn => functions.push(self.function()?),
|
||||
TokenKind::Ctor => {
|
||||
maybe_ctor.replace(self.constructor()?);
|
||||
}
|
||||
_ => {
|
||||
let lookahead = self.lookahead.as_ref().unwrap();
|
||||
return Err(vec![Diagnostic::new(
|
||||
&format!(
|
||||
"Expected any of {:?}; found {:?}",
|
||||
[TokenKind::Mut, TokenKind::Identifier, TokenKind::Fn],
|
||||
lookahead.kind()
|
||||
),
|
||||
lookahead.start(),
|
||||
lookahead.end(),
|
||||
)]);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
@ -504,6 +526,56 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn constructor(&mut self) -> Result<Constructor, Vec<Diagnostic>> {
|
||||
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
||||
self.advance();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let ctor_keyword = self.expect_advance(TokenKind::Ctor)?;
|
||||
self.expect_advance(TokenKind::LeftParentheses)?;
|
||||
|
||||
let parameters = if self.current.is_some() && self.peek_current(TokenKind::Identifier) {
|
||||
self.parameter_list()?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
self.expect_advance(TokenKind::RightParentheses)?;
|
||||
|
||||
// statements
|
||||
let mut statements: Vec<Statement> = vec![];
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
while self.current.is_some()
|
||||
&& matches_statement_first!(self.current.as_ref().unwrap().kind())
|
||||
{
|
||||
match self.statement() {
|
||||
Ok(statement) => {
|
||||
statements.push(statement);
|
||||
}
|
||||
Err(mut statement_diagnostics) => {
|
||||
diagnostics.append(&mut statement_diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.expect_advance(TokenKind::End)?;
|
||||
|
||||
if diagnostics.is_empty() {
|
||||
Ok(Constructor::new(
|
||||
is_public,
|
||||
SourceRange::new(ctor_keyword.start(), ctor_keyword.end()),
|
||||
parameters,
|
||||
statements,
|
||||
))
|
||||
} else {
|
||||
Err(diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
fn field(&mut self) -> Result<Field, Vec<Diagnostic>> {
|
||||
let is_public = if self.current.is_some() && self.peek_current(TokenKind::Public) {
|
||||
self.advance();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
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::cell::RefCell;
|
||||
@ -11,6 +12,7 @@ pub struct ClassScope {
|
||||
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 {
|
||||
@ -21,6 +23,7 @@ impl ClassScope {
|
||||
class_symbols: HashMap::new(),
|
||||
field_symbols: HashMap::new(),
|
||||
function_symbols: HashMap::new(),
|
||||
constructor_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +51,14 @@ impl ClassScope {
|
||||
&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 {
|
||||
self.parent_id
|
||||
}
|
||||
|
||||
47
dmc-lib/src/symbol/constructor_symbol.rs
Normal file
47
dmc-lib/src/symbol/constructor_symbol.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use crate::source_range::SourceRange;
|
||||
use crate::symbol::Symbol;
|
||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct ConstructorSymbol {
|
||||
ctor_keyword_source_range: SourceRange,
|
||||
is_extern: bool,
|
||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||
}
|
||||
|
||||
impl ConstructorSymbol {
|
||||
pub fn new(ctor_keyword_source_range: SourceRange, is_extern: bool) -> Self {
|
||||
Self {
|
||||
ctor_keyword_source_range,
|
||||
is_extern,
|
||||
parameters: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
||||
self.parameters = Some(parameters);
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
|
||||
self.parameters.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn is_extern(&self) -> bool {
|
||||
self.is_extern
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol for ConstructorSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
"ctor"
|
||||
}
|
||||
|
||||
fn declared_name_owned(&self) -> Rc<str> {
|
||||
Rc::from(self.declared_name())
|
||||
}
|
||||
|
||||
fn declared_name_source_range(&self) -> &SourceRange {
|
||||
&self.ctor_keyword_source_range
|
||||
}
|
||||
}
|
||||
@ -19,12 +19,8 @@ pub enum ExpressibleSymbol {
|
||||
impl ExpressibleSymbol {
|
||||
pub fn type_info(&self) -> TypeInfo {
|
||||
match self {
|
||||
ExpressibleSymbol::Class(class_symbol) => {
|
||||
todo!()
|
||||
}
|
||||
ExpressibleSymbol::Field(field_symbol) => {
|
||||
todo!()
|
||||
}
|
||||
ExpressibleSymbol::Class(class_symbol) => TypeInfo::Class(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!
|
||||
}
|
||||
|
||||
@ -17,6 +17,14 @@ impl FieldSymbol {
|
||||
type_info: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
||||
self.type_info = Some(type_info);
|
||||
}
|
||||
|
||||
pub fn type_info(&self) -> &TypeInfo {
|
||||
self.type_info.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol for FieldSymbol {
|
||||
|
||||
@ -2,6 +2,7 @@ use crate::source_range::SourceRange;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod class_symbol;
|
||||
pub mod constructor_symbol;
|
||||
pub mod expressible_symbol;
|
||||
pub mod field_symbol;
|
||||
pub mod function_symbol;
|
||||
|
||||
@ -7,6 +7,7 @@ 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::constructor_symbol::ConstructorSymbol;
|
||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||
use crate::symbol::field_symbol::FieldSymbol;
|
||||
use crate::symbol::function_symbol::FunctionSymbol;
|
||||
@ -123,6 +124,32 @@ impl SymbolTable {
|
||||
Ok(to_return)
|
||||
}
|
||||
|
||||
pub fn insert_constructor_symbol(
|
||||
&mut self,
|
||||
constructor_symbol: ConstructorSymbol,
|
||||
) -> Result<Rc<RefCell<ConstructorSymbol>>, SymbolInsertError> {
|
||||
let maybe_already_inserted = match self.current_scope() {
|
||||
Scope::Class(class_scope) => class_scope.constructor_symbol(),
|
||||
_ => 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(
|
||||
&mut self,
|
||||
field_symbol: FieldSymbol,
|
||||
|
||||
@ -47,4 +47,5 @@ pub enum TokenKind {
|
||||
SelfKw,
|
||||
Public,
|
||||
Mut,
|
||||
Ctor,
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user