diff --git a/ast-generator/src/deserialize/struct_spec.rs b/ast-generator/src/deserialize/struct_spec.rs index e141aaa..cb0685a 100644 --- a/ast-generator/src/deserialize/struct_spec.rs +++ b/ast-generator/src/deserialize/struct_spec.rs @@ -9,16 +9,15 @@ fn deserialize_field(field_yaml: &Yaml) -> StructField { let (name, props) = unwrap_single_member_hash(field_yaml); let kind = props["kind"].as_str().unwrap(); let wrap = if let Some(wrap) = props["wrap"].as_str() { - match wrap { - "rc_ref_cell" => { - Some(StructFieldWrap::RcRefCell) - } - _ => panic!() + match wrap { + "rc_ref_cell" => Some(StructFieldWrap::RcRefCell), + _ => panic!(), } } else { None }; - StructField::new(&name, kind, wrap) + let vec = get_as_bool(&props["vec"]); + StructField::new(&name, kind, wrap, vec) } fn deserialize_skip_child(props: &Yaml) -> StructChild { @@ -112,8 +111,12 @@ fn deserialize_special_child(name: &str, props: &Yaml) -> StructChild { match props["kind"].as_str().unwrap() { "file_id" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::FileId)), "range" => StructChild::Special(SpecialChild::new(name, SpecialChildKind::Range)), - _ => panic!("Invalid special child kind {} in {}", props["kind"].as_str().unwrap(), name), - } + _ => panic!( + "Invalid special child kind {} in {}", + props["kind"].as_str().unwrap(), + name + ), + } } fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild { @@ -124,7 +127,7 @@ fn deserialize_hash_child(name: &str, props: &Yaml) -> StructChild { } else if props["member"].is_hash() { deserialize_member_child(name, &props["member"]) } else if props["special"].is_hash() { - deserialize_special_child(name, &props["special"]) + deserialize_special_child(name, &props["special"]) } else { panic!("Expected 'skip' or 'vec' in 'member' in {}", name); } @@ -167,9 +170,10 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec { } else { deserialize_error!("array", "children", name); }; - + let fields = if struct_yaml["fields"].is_array() { - struct_yaml["fields"].as_vec() + struct_yaml["fields"] + .as_vec() .unwrap() .iter() .map(|field| deserialize_field(field)) @@ -178,9 +182,10 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec { } else { vec![] }; - + let derive = if struct_yaml["derive"].is_array() { - struct_yaml["derive"].as_vec() + struct_yaml["derive"] + .as_vec() .unwrap() .iter() .map(|derive| derive.as_str().unwrap().to_string()) @@ -188,6 +193,6 @@ pub fn deserialize_struct_spec(name: &str, struct_yaml: &Yaml) -> StructSpec { } else { vec![] }; - + StructSpec::new(name, children, fields, derive) } diff --git a/ast-generator/src/spec/struct_spec.rs b/ast-generator/src/spec/struct_spec.rs index 06b842f..7ec8949 100644 --- a/ast-generator/src/spec/struct_spec.rs +++ b/ast-generator/src/spec/struct_spec.rs @@ -6,7 +6,12 @@ pub struct StructSpec { } impl StructSpec { - pub fn new(build: &str, children: Vec>, fields: Vec>, derive: Vec) -> Self { + pub fn new( + build: &str, + children: Vec>, + fields: Vec>, + derive: Vec, + ) -> Self { Self { build: build.to_string(), children, @@ -24,11 +29,11 @@ impl StructSpec { pub fn children(&self) -> impl Iterator { self.children.iter().map(Box::as_ref) } - + pub fn fields(&self) -> impl Iterator { self.fields.iter().map(Box::as_ref) } - + pub fn derive(&self) -> &[String] { &self.derive } @@ -48,13 +53,11 @@ impl StructChild { _ => false, } } - + pub fn unwrap_special(&self) -> Option<&SpecialChild> { match self { - StructChild::Special(special_child) => { - Some(special_child) - }, - _ => None + StructChild::Special(special_child) => Some(special_child), + _ => None, } } } @@ -254,14 +257,14 @@ impl SpecialChild { pub fn new(name: &str, kind: SpecialChildKind) -> Self { Self { name: name.to_string(), - kind + kind, } } - + pub fn name(&self) -> &str { &self.name } - + pub fn kind(&self) -> &SpecialChildKind { &self.kind } @@ -278,31 +281,37 @@ pub struct StructField { name: String, kind: String, wrap: Option, + vec: bool, } impl StructField { - pub fn new(name: &str, kind: &str, wrap: Option) -> Self { + pub fn new(name: &str, kind: &str, wrap: Option, vec: bool) -> Self { Self { name: name.to_string(), kind: kind.to_string(), wrap, + vec, } } - + pub fn name(&self) -> &str { &self.name } - + pub fn kind(&self) -> &str { &self.kind } - + pub fn wrap(&self) -> Option<&StructFieldWrap> { self.wrap.as_ref() } + + pub fn vec(&self) -> bool { + self.vec + } } #[derive(Debug)] pub enum StructFieldWrap { - RcRefCell + RcRefCell, } diff --git a/ast-generator/src/type_gen/struct_type.rs b/ast-generator/src/type_gen/struct_type.rs index e3d450d..e015ba2 100644 --- a/ast-generator/src/type_gen/struct_type.rs +++ b/ast-generator/src/type_gen/struct_type.rs @@ -19,35 +19,51 @@ fn make_field_accessors(field: &StructField) -> TokenStream { quote! { #inner } } }; - let set_field_ident = format_ident!("set_{}", field.name()); let field_ident_mut = format_ident!("{}_mut", field.name()); - quote! { - pub fn #field_ident(&self) -> Option<&#field_type> { - self.#field_ident.as_ref() - } - - pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> { - self.#field_ident.as_mut() - } + if field.vec() { + quote! { + pub fn #field_ident(&self) -> &[#field_type] { + self.#field_ident.as_slice() + } - pub fn #set_field_ident(&mut self, #field_ident: #field_type) { - self.#field_ident = Some(#field_ident); + pub fn #field_ident_mut(&mut self) -> &mut Vec<#field_type> { + &mut self.#field_ident + } + } + } else { + let set_field_ident = format_ident!("set_{}", field.name()); + quote! { + pub fn #field_ident(&self) -> Option<&#field_type> { + self.#field_ident.as_ref() + } + + pub fn #field_ident_mut(&mut self) -> Option<&mut #field_type> { + self.#field_ident.as_mut() + } + + pub fn #set_field_ident(&mut self, #field_ident: #field_type) { + self.#field_ident = Some(#field_ident); + } } } } fn make_field_initializer(field: &StructField) -> TokenStream { let field_ident = format_ident!("{}", field.name()); - quote! { #field_ident: None } + if field.vec() { + quote! { #field_ident: vec![] } + } else { + quote! { #field_ident: None } + } } fn make_annotated_field(field: &StructField) -> TokenStream { let field_ident = format_ident!("{}", field.name()); let field_type = if let Some(wrap) = field.wrap() { + let inner = format_ident!("{}", field.kind()); match wrap { StructFieldWrap::RcRefCell => { - let inner = format_ident!("{}", field.kind()); quote! { Rc> } } } @@ -56,8 +72,14 @@ fn make_annotated_field(field: &StructField) -> TokenStream { quote! { #inner } }; - quote! { - #field_ident: Option<#field_type> + if field.vec() { + quote! { + #field_ident: Vec<#field_type> + } + } else { + quote! { + #field_ident: Option<#field_type> + } } } diff --git a/src/name_analysis/first_pass.rs b/src/name_analysis/first_pass.rs index c3041c8..d9890e4 100644 --- a/src/name_analysis/first_pass.rs +++ b/src/name_analysis/first_pass.rs @@ -3,50 +3,17 @@ use crate::diagnostic::DmDiagnostic; use crate::name_analysis::fqn_context::FqnContext; use crate::name_analysis::symbol::source_definition::SourceDefinition; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; -use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; +use crate::name_analysis::symbol_table::SymbolTable; use crate::name_analysis::symbol_tree::SymbolTree; -use crate::name_analysis::util::use_statement_base_fqn; -use codespan_reporting::diagnostic::{Diagnostic, Label}; +use crate::name_analysis::util; +use crate::name_analysis::util::{handle_insert_error, use_statement_base_fqn}; use std::cell::RefCell; -use std::range::Range; use std::rc::Rc; -fn handle_insert_error( - err: SymbolInsertError, - error_symbol_name: &str, - error_file_id: usize, - error_range: Range, - symbol_types: &str, - diagnostics: &mut Vec, -) { - match err { - SymbolInsertError::SymbolAlreadyDefined(s) => { - let mut diagnostic = Diagnostic::error() - .with_message(format!( - "{} symbol '{}' already defined in the current scope.", - symbol_types, error_symbol_name, - )) - .with_label( - Label::primary(error_file_id, error_range) - .with_message("Symbol duplicated here."), - ); - - if let Some(source_definition) = s.definition() { - diagnostic = diagnostic.with_label( - Label::secondary(source_definition.file_id(), source_definition.range()) - .with_message("Symbol defined here."), - ); - } - - diagnostics.push(diagnostic); - } - } -} - macro_rules! insert_symbol { ($insert_method:ident, $symbol:expr, $symbol_table:ident, $name:expr, $node:ident, $symbol_kinds:literal, $diagnostics:ident) => { if let Err(insert_error) = $symbol_table.$insert_method($symbol) { - handle_insert_error( + util::handle_insert_error( insert_error, $name, $node.file_id(), @@ -58,20 +25,6 @@ macro_rules! insert_symbol { }; } -macro_rules! insert_concrete_use_symbol { - ($symbol:expr, $symbol_table:ident, $symbol_name:expr, $source_node:ident, $symbol_kinds:literal, $diagnostics:ident) => { - insert_symbol!( - insert_concrete_use_symbol, - $symbol, - $symbol_table, - $symbol_name, - $source_node, - $symbol_kinds, - $diagnostics - ) - }; -} - pub fn nap1_compilation_unit( file_name: &str, compilation_unit: &mut CompilationUnit, @@ -95,12 +48,12 @@ pub fn nap1_compilation_unit( symbol_table.pop_scope(); } -fn handle_concrete_use_statement( - use_statement: &mut UseStatement, +fn maybe_insert_concrete_use_symbol( + use_statement: &UseStatement, identifier: &Identifier, symbol_table: &mut SymbolTable, diagnostics: &mut Vec, -) { +) -> Option>> { let base_fqn = use_statement_base_fqn(use_statement); let to_insert = ConcreteUseSymbol::new( &base_fqn, @@ -108,9 +61,7 @@ fn handle_concrete_use_statement( Some(SourceDefinition::from_identifier(identifier)), ); match symbol_table.insert_concrete_use_symbol(to_insert) { - Ok(inserted) => { - use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(inserted)))); - } + Ok(inserted) => Some(inserted), Err(insert_error) => { handle_insert_error( insert_error, @@ -120,6 +71,7 @@ fn handle_concrete_use_statement( "Use Symbol", diagnostics, ); + None } } } @@ -133,54 +85,51 @@ fn nap1_use_statement( match use_statement.suffix() { UseStatementSuffix::Identifier(identifier) => { - insert_concrete_use_symbol!( - ConcreteUseSymbol::new( - &base_fqn, - identifier.name(), - Some(SourceDefinition::from_identifier(identifier)) - ), + let maybe_symbol = maybe_insert_concrete_use_symbol( + use_statement, + &identifier, symbol_table, - &base_fqn, - identifier, - "Use Statement", - diagnostics + diagnostics, ); - use_statement.set_use_symbol(Rc::new(RefCell::new(UseSymbol::Concrete(Rc::new( - RefCell::new(ConcreteUseSymbol::new( - &base_fqn, - identifier.name(), - Some(SourceDefinition::from_use_statement(use_statement)), - )), - ))))); + if let Some(concrete_use_symbol) = maybe_symbol { + use_statement.use_symbols_mut().push(UseSymbol::Concrete(concrete_use_symbol)); + } } UseStatementSuffix::Star => { - insert_symbol!( - insert_star_use_symbol, - StarUseSymbol::new( - &base_fqn, - Some(SourceDefinition::from_use_statement(use_statement)) - ), - symbol_table, - &base_fqn, - use_statement, - "Use Statement", - diagnostics - ); + let maybe_symbol = match symbol_table.insert_star_use_symbol( + StarUseSymbol::new(&base_fqn, Some(SourceDefinition::from_use_statement(use_statement))) + ) { + Ok(inserted) => { + Some(todo!()) + }, + Err(insert_error) => { + handle_insert_error( + insert_error, + &base_fqn, + use_statement.file_id(), + use_statement.range(), + "Star Use Symbol", + diagnostics, + ); + None + } + }; } UseStatementSuffix::UseList(use_list) => { - for identifier in use_list.identifiers() { - insert_concrete_use_symbol!( - ConcreteUseSymbol::new( - &base_fqn, - identifier.name(), - Some(SourceDefinition::from_identifier(identifier)) - ), - symbol_table, - &base_fqn, - identifier, - "Use Statement", - diagnostics - ); + let maybe_symbols = use_list.identifiers() + .map(|identifier| { + maybe_insert_concrete_use_symbol( + use_statement, + identifier, + symbol_table, + diagnostics, + ) + }) + .collect::>(); + for maybe_symbol in maybe_symbols { + if let Some(symbol) = maybe_symbol { + use_statement.use_symbols_mut().push(UseSymbol::Concrete(symbol)); + } } } } diff --git a/src/name_analysis/second_pass.rs b/src/name_analysis/second_pass.rs index 53a93cd..b4be3fd 100644 --- a/src/name_analysis/second_pass.rs +++ b/src/name_analysis/second_pass.rs @@ -1,34 +1,12 @@ use crate::ast::node::{CompilationUnit, Identifier, UseStatement, UseStatementSuffix}; use crate::diagnostic::DmDiagnostic; -use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; -use crate::name_analysis::symbol::use_symbol::UseSymbol; +use crate::name_analysis::symbol::usable_symbol::UsableSymbol; +use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, UseSymbol}; use crate::name_analysis::symbol_table::{SymbolLookupError, SymbolTable}; use crate::name_analysis::symbol_tree::SymbolTree; -use codespan_reporting::diagnostic::{Diagnostic, Label}; -use std::range::Range; - -fn handle_lookup_error( - err: SymbolLookupError, - error_symbol_name: &str, - error_file_id: usize, - error_range: Range, - symbol_types: &str, - diagnostics: &mut Vec, -) { - match err { - SymbolLookupError::NoDefinition => { - let diagnostic = Diagnostic::error() - .with_message(format!( - "No such {} symbol '{}' in scope.", - symbol_types, error_symbol_name, - )) - .with_label( - Label::primary(error_file_id, error_range).with_message("Symbol used here."), - ); - diagnostics.push(diagnostic); - } - } -} +use crate::name_analysis::util::{handle_lookup_error, use_statement_base_fqn}; +use std::cell::RefCell; +use std::rc::Rc; pub fn nap2_compilation_unit( compilation_unit: &mut CompilationUnit, @@ -44,13 +22,12 @@ pub fn nap2_compilation_unit( // TODO: declarations } -fn handle_concrete_use_symbol( +fn find_usable_symbol( use_statement: &UseStatement, identifier: &Identifier, symbol_tree: &SymbolTree, - diagnostics: &mut Vec, -) { - let mut fqn_parts: Vec<&str> = { +) -> Option { + let fqn_parts: Vec<&str> = { let mut base: Vec<&str> = use_statement .prefixes() .map(|prefix| prefix.identifier().name()) @@ -58,36 +35,67 @@ fn handle_concrete_use_symbol( base.push(identifier.name()); base }; - let found = symbol_tree + symbol_tree .find_interface(&fqn_parts) - .map(|interface_symbol| ConcreteUsableSymbol::Interface(interface_symbol)) + .map(|interface_symbol| UsableSymbol::Interface(interface_symbol)) .or_else(|| { symbol_tree .find_class(&fqn_parts) - .map(|class_symbol| ConcreteUsableSymbol::Class(class_symbol)) + .map(|class_symbol| UsableSymbol::Class(class_symbol)) }) .or_else(|| { symbol_tree .find_function(&fqn_parts) - .map(|function_symbol| ConcreteUsableSymbol::Function(function_symbol)) - }); - if let Some(concrete_usable_symbol) = found { - let use_symbol_ref = use_statement.use_symbol().unwrap().borrow(); - match *use_symbol_ref { - UseSymbol::Concrete(ref concrete_use_symbol) => { - concrete_use_symbol - .borrow_mut() - .set_resolved_symbol(concrete_usable_symbol); + .map(|function_symbol| UsableSymbol::Function(function_symbol)) + }) +} + +fn find_matching_concrete_use_symbol( + use_statement: &UseStatement, + identifier: &Identifier, +) -> Option>> { + let base_fqn = use_statement_base_fqn(use_statement); + use_statement + .use_symbols() + .iter() + .find(|use_symbol| match use_symbol { + UseSymbol::Concrete(concrete_use_symbol) => { + let borrowed = concrete_use_symbol.borrow(); + borrowed.base_fqn() == base_fqn && borrowed.declared_name() == identifier.name() } - _ => panic!( - "Unexpected UseSymbol type (expected Concrete, found: {:?}", - *use_symbol_ref - ), + _ => false, + }) + .map(|use_symbol| match use_symbol { + UseSymbol::Concrete(concrete) => concrete.clone(), + _ => panic!(), + }) +} + +fn handle_concrete_use( + use_statement: &UseStatement, + identifier: &Identifier, + symbol_tree: &SymbolTree, + diagnostics: &mut Vec, +) { + let maybe_usable_symbol = find_usable_symbol(use_statement, identifier, symbol_tree); + if let Some(usable_symbol) = maybe_usable_symbol { + let maybe_concrete_use_symbol = + find_matching_concrete_use_symbol(use_statement, identifier); + if let Some(concrete_use_symbol) = maybe_concrete_use_symbol { + concrete_use_symbol + .borrow_mut() + .set_resolved_symbol(usable_symbol); + } else { + panic!("Can't find matching ConcreteUseSymbol"); } } else { handle_lookup_error( SymbolLookupError::NoDefinition, - &fqn_parts.join("::"), + &format!( + "{}::{}", + use_statement_base_fqn(use_statement), + identifier.name() + ), use_statement.file_id(), use_statement.range(), "Usable Symbol", @@ -103,14 +111,14 @@ fn nap2_use_statement( ) { match use_statement.suffix() { UseStatementSuffix::Identifier(identifier) => { - handle_concrete_use_symbol(use_statement, identifier, symbol_tree, diagnostics); + handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics); } UseStatementSuffix::Star => { todo!("Resolve star symbols") } UseStatementSuffix::UseList(use_list) => { for identifier in use_list.identifiers() { - handle_concrete_use_symbol(use_statement, identifier, symbol_tree, diagnostics); + handle_concrete_use(use_statement, identifier, symbol_tree, diagnostics); } } } diff --git a/src/name_analysis/symbol/usable_symbol.rs b/src/name_analysis/symbol/usable_symbol.rs index 7988d50..ccc7c77 100644 --- a/src/name_analysis/symbol/usable_symbol.rs +++ b/src/name_analysis/symbol/usable_symbol.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use std::rc::Rc; #[derive(Clone, Debug)] -pub enum ConcreteUsableSymbol { +pub enum UsableSymbol { Interface(Rc>), Class(Rc>), Function(Rc>), diff --git a/src/name_analysis/symbol/use_symbol.rs b/src/name_analysis/symbol/use_symbol.rs index d9d59da..182a38a 100644 --- a/src/name_analysis/symbol/use_symbol.rs +++ b/src/name_analysis/symbol/use_symbol.rs @@ -1,5 +1,5 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition; -use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; +use crate::name_analysis::symbol::usable_symbol::UsableSymbol; use std::cell::RefCell; use std::fmt::{Debug, Formatter}; use std::rc::Rc; @@ -24,7 +24,7 @@ pub struct ConcreteUseSymbol { base_fqn: String, declared_name: String, source_definition: Option, - resolved_symbol: Option, + resolved_symbol: Option, } impl ConcreteUseSymbol { @@ -53,11 +53,11 @@ impl ConcreteUseSymbol { self.source_definition.as_ref() } - pub fn resolved_symbol(&self) -> Option<&ConcreteUsableSymbol> { + pub fn resolved_symbol(&self) -> Option<&UsableSymbol> { self.resolved_symbol.as_ref() } - pub fn set_resolved_symbol(&mut self, symbol: ConcreteUsableSymbol) { + pub fn set_resolved_symbol(&mut self, symbol: UsableSymbol) { self.resolved_symbol = Some(symbol); } } diff --git a/src/name_analysis/symbol_table/mod.rs b/src/name_analysis/symbol_table/mod.rs index ea04716..e6cde8f 100644 --- a/src/name_analysis/symbol_table/mod.rs +++ b/src/name_analysis/symbol_table/mod.rs @@ -2,7 +2,6 @@ use crate::name_analysis::symbol::class_member_symbol::ClassMemberSymbol; use crate::name_analysis::symbol::function_symbol::FunctionSymbol; use crate::name_analysis::symbol::module_symbol::ModuleSymbol; use crate::name_analysis::symbol::parameter_symbol::ParameterSymbol; -use crate::name_analysis::symbol::usable_symbol::ConcreteUsableSymbol; use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol, UseSymbol}; use crate::name_analysis::symbol::variable_symbol::VariableSymbol; use crate::name_analysis::symbol::*; @@ -10,7 +9,6 @@ use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; use scope::Scope; use std::cell::RefCell; -use std::collections::VecDeque; use std::fmt::Display; use std::ops::Deref; use std::rc::Rc; @@ -81,10 +79,6 @@ impl SymbolTable { .cloned() } - fn find_current_scope_star_use_symbol(&self, base_fqn: &str) -> Option<&StarUseSymbol> { - self.current_scope().star_use_symbols().get(base_fqn) - } - fn find_current_scope_module_symbol(&self, declared_name: &str) -> Option<&ModuleSymbol> { self.current_scope().module_symbols().get(declared_name) } @@ -158,19 +152,11 @@ impl SymbolTable { pub fn insert_star_use_symbol( &mut self, star_use_symbol: StarUseSymbol, - ) -> Result<(), SymbolInsertError> { - if let Some(defined_symbol) = - self.find_current_scope_star_use_symbol(star_use_symbol.base_fqn()) - { - Err(SymbolAlreadyDefined(Symbol::Use(UseSymbol::Star( - defined_symbol.clone(), - )))) - } else { - self.current_scope_mut() - .star_use_symbols_mut() - .insert(star_use_symbol.base_fqn().to_string(), star_use_symbol); - Ok(()) - } + ) -> Result>, SymbolInsertError> { + let inserted = self + .current_scope_mut() + .insert_star_use_symbol(star_use_symbol); + Ok(inserted) } pub fn insert_module_symbol( diff --git a/src/name_analysis/symbol_table/scope.rs b/src/name_analysis/symbol_table/scope.rs index 253c055..de8157d 100644 --- a/src/name_analysis/symbol_table/scope.rs +++ b/src/name_analysis/symbol_table/scope.rs @@ -17,7 +17,7 @@ pub struct Scope { id: usize, children: Vec, concrete_use_symbols: HashMap>>, - star_use_symbols: HashMap, + star_use_symbols: HashMap>>, module_symbols: HashMap, interface_symbols: HashMap, Rc>>, class_symbols: HashMap, Rc>>, @@ -72,13 +72,11 @@ impl Scope { ) -> &mut HashMap>> { &mut self.concrete_use_symbols } - - pub fn star_use_symbols(&self) -> &HashMap { - &self.star_use_symbols - } - - pub fn star_use_symbols_mut(&mut self) -> &mut HashMap { - &mut self.star_use_symbols + + pub fn insert_star_use_symbol(&mut self, symbol: StarUseSymbol) -> Rc> { + let as_rc = Rc::new(RefCell::new(symbol)); + self.star_use_symbols.insert(as_rc.borrow().base_fqn().to_string(), as_rc.clone()); + as_rc.clone() } pub fn module_symbols(&self) -> &HashMap { @@ -167,7 +165,7 @@ impl Display for Scope { self.debug_name() )?; write_symbols!(f, self.concrete_use_symbols()); - write_symbols!(f, self.star_use_symbols()); + todo!("self.star_use_symbols"); write_symbols!(f, self.module_symbols()); todo!("self.concrete_type_symbols"); write_symbols!(f, self.function_symbols()); diff --git a/src/name_analysis/util.rs b/src/name_analysis/util.rs index c835589..a2b4850 100644 --- a/src/name_analysis/util.rs +++ b/src/name_analysis/util.rs @@ -1,11 +1,68 @@ use crate::ast::node::UseStatement; +use crate::diagnostic::DmDiagnostic; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError}; +use codespan_reporting::diagnostic::{Diagnostic, Label}; +use std::range::Range; -pub fn use_statement_base_fqn( - use_statement: &UseStatement -) -> String { +pub fn use_statement_base_fqn(use_statement: &UseStatement) -> String { use_statement .prefixes() .map(|prefix| prefix.identifier().name()) .collect::>() .join("::") -} \ No newline at end of file +} + +pub fn handle_insert_error( + err: SymbolInsertError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut Vec, +) { + match err { + SymbolInsertError::SymbolAlreadyDefined(s) => { + let mut diagnostic = Diagnostic::error() + .with_message(format!( + "{} symbol '{}' already defined in the current scope.", + symbol_types, error_symbol_name, + )) + .with_label( + Label::primary(error_file_id, error_range) + .with_message("Symbol duplicated here."), + ); + + if let Some(source_definition) = s.definition() { + diagnostic = diagnostic.with_label( + Label::secondary(source_definition.file_id(), source_definition.range()) + .with_message("Symbol defined here."), + ); + } + + diagnostics.push(diagnostic); + } + } +} + +pub fn handle_lookup_error( + err: SymbolLookupError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut Vec, +) { + match err { + SymbolLookupError::NoDefinition => { + let diagnostic = Diagnostic::error() + .with_message(format!( + "No such {} symbol '{}' in scope.", + symbol_types, error_symbol_name, + )) + .with_label( + Label::primary(error_file_id, error_range).with_message("Symbol used here."), + ); + diagnostics.push(diagnostic); + } + } +} diff --git a/src/parser/ast.yaml b/src/parser/ast.yaml index 2992818..d593336 100644 --- a/src/parser/ast.yaml +++ b/src/parser/ast.yaml @@ -249,9 +249,9 @@ UseStatement: special: kind: range fields: - - use_symbol: + - use_symbols: kind: UseSymbol - wrap: rc_ref_cell + vec: true UseStatementPrefix: struct: children: