Better handling of global imports.
This commit is contained in:
parent
6bcef184eb
commit
da05bb101b
@ -1,8 +1,7 @@
|
||||
use crate::ast::node::{
|
||||
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, FunctionBody
|
||||
, Identifier, IdentifierOrFqn, Module, ModuleLevelDeclaration
|
||||
, StarUseStatement, UseStatement,
|
||||
UseStatementIdentifier, UseStatementPrefix,
|
||||
CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix, Function, Identifier,
|
||||
IdentifierOrFqn, Module, ModuleLevelDeclaration, PlatformFunction, StarUseStatement,
|
||||
UseStatement, UseStatementIdentifier, UseStatementPrefix,
|
||||
};
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol::function_symbol::FunctionSymbol;
|
||||
@ -11,10 +10,9 @@ use crate::name_analysis::symbol::module_symbol::ModuleSymbol;
|
||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use crate::name_analysis::util::{
|
||||
handle_insert_error, join_fqn_parts,
|
||||
};
|
||||
use crate::name_analysis::util::{handle_insert_error, join_fqn_parts};
|
||||
use std::cell::RefCell;
|
||||
use std::process::id;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn na_p1_compilation_unit(
|
||||
@ -26,13 +24,26 @@ pub fn na_p1_compilation_unit(
|
||||
if let Some(namespace) = compilation_unit.namespace() {
|
||||
match namespace.identifier_or_fqn() {
|
||||
IdentifierOrFqn::Identifier(identifier) => {
|
||||
symbol_table.set_current_fqn(&[identifier.name()])
|
||||
symbol_table.set_current_fqn(&[identifier.name()]);
|
||||
}
|
||||
IdentifierOrFqn::FullyQualifiedName(fqn) => {
|
||||
symbol_table
|
||||
.set_current_fqn(&fqn.identifiers().map(Identifier::name).collect::<Vec<_>>());
|
||||
}
|
||||
}
|
||||
let fqn_parts = match namespace.identifier_or_fqn() {
|
||||
IdentifierOrFqn::Identifier(identifier) => {
|
||||
vec![identifier.name()]
|
||||
}
|
||||
IdentifierOrFqn::FullyQualifiedName(fqn) => {
|
||||
let mut parts = vec![];
|
||||
for identifier in fqn.identifiers() {
|
||||
parts.push(identifier.name());
|
||||
}
|
||||
parts
|
||||
}
|
||||
};
|
||||
symbol_table.register_module(&fqn_parts);
|
||||
} else {
|
||||
symbol_table.set_current_fqn(&[]);
|
||||
}
|
||||
@ -187,7 +198,9 @@ fn na_p1_module_level_declaration(
|
||||
.map(|function_symbol| ModuleLevelSymbol::Function(function_symbol))
|
||||
}
|
||||
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
|
||||
todo!()
|
||||
na_p1_platform_function(platform_function, symbol_table, diagnostics).map(
|
||||
|platform_function_symbol| ModuleLevelSymbol::Function(platform_function_symbol),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -264,7 +277,7 @@ fn na_p1_function(
|
||||
if maybe_function_symbol.is_some() {
|
||||
function.set_function_symbol(maybe_function_symbol.as_ref().unwrap().clone());
|
||||
}
|
||||
|
||||
|
||||
// create a scope for this function
|
||||
symbol_table.push_scope(&format!("FunctionScope {}", function.identifier().name()));
|
||||
function.set_scope_id(symbol_table.current_scope_id());
|
||||
@ -272,3 +285,45 @@ fn na_p1_function(
|
||||
|
||||
maybe_function_symbol
|
||||
}
|
||||
|
||||
fn na_p1_platform_function(
|
||||
platform_function: &mut PlatformFunction,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) -> Option<Rc<RefCell<FunctionSymbol>>> {
|
||||
let to_insert = FunctionSymbol::new(
|
||||
&symbol_table.resolve_fqn(Rc::from(platform_function.identifier().name())),
|
||||
platform_function.is_public(),
|
||||
true,
|
||||
Some(SourceDefinition::from_identifier(
|
||||
platform_function.identifier(),
|
||||
)),
|
||||
);
|
||||
let maybe_function_symbol = match symbol_table.insert_function_symbol(to_insert) {
|
||||
Ok(function_symbol) => Some(function_symbol),
|
||||
Err(symbol_insert_error) => {
|
||||
handle_insert_error(
|
||||
symbol_insert_error,
|
||||
platform_function.identifier().name(),
|
||||
platform_function.identifier().file_id(),
|
||||
platform_function.identifier().range(),
|
||||
diagnostics,
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if maybe_function_symbol.is_some() {
|
||||
platform_function.set_function_symbol(maybe_function_symbol.as_ref().unwrap().clone());
|
||||
}
|
||||
|
||||
// create a scope for later
|
||||
symbol_table.push_scope(&format!(
|
||||
"PlatformFunctionScope {}",
|
||||
platform_function.identifier().name()
|
||||
));
|
||||
platform_function.set_scope_id(symbol_table.current_scope_id());
|
||||
symbol_table.pop_scope();
|
||||
|
||||
maybe_function_symbol
|
||||
}
|
||||
|
||||
@ -46,7 +46,9 @@ pub fn analyze_names<
|
||||
) -> Vec<DmDiagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
// gather symbols
|
||||
// first pass
|
||||
// generally, gather symbols from declarations
|
||||
// don't go into functions
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
let file_name = files.name(compilation_unit.file_id()).unwrap();
|
||||
na_p1_compilation_unit(file_name, compilation_unit, symbol_table, &mut diagnostics);
|
||||
@ -56,7 +58,11 @@ pub fn analyze_names<
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
// resolve symbols
|
||||
// resolve global imports
|
||||
symbol_table.resolve_global_imports();
|
||||
|
||||
// second pass
|
||||
// resolve referenced symbols and go into functions
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
na_p2_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||
}
|
||||
@ -318,12 +324,39 @@ mod tests {
|
||||
|
||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std/core symbols.");
|
||||
|
||||
let resolved_std_core_symbols = symbol_table
|
||||
.find_usable_symbols_by_base_fqn(&str_slice_to_rcs(&["std", "core"]))
|
||||
.unwrap();
|
||||
global_std_core_star_use
|
||||
.borrow_mut()
|
||||
.set_resolved_symbols(resolved_std_core_symbols);
|
||||
assert_no_diagnostics(sources, &mut symbol_table);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_std_core_source() {
|
||||
let sources = HashMap::from([
|
||||
(
|
||||
"std/core/print.dm",
|
||||
"
|
||||
ns std::core
|
||||
|
||||
pub platform fn println(msg: Any) -> Void
|
||||
|
||||
pub platform fn print(msg: Any) -> Void
|
||||
",
|
||||
),
|
||||
(
|
||||
"main.dm",
|
||||
"
|
||||
fn main()
|
||||
println('A line')
|
||||
print('Not a line')
|
||||
end
|
||||
",
|
||||
),
|
||||
]);
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let global_star_use = symbol_table
|
||||
.insert_star_use_symbol(StarUseSymbol::new(
|
||||
&str_slice_to_rcs(&["std", "core"]),
|
||||
None,
|
||||
))
|
||||
.expect("Failed to insert star use symbol.");
|
||||
|
||||
assert_no_diagnostics(sources, &mut symbol_table);
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::ast::node::{
|
||||
AssignmentStatement, Call, CompilationUnit, ConcreteUseStatement, ConcreteUseStatementSuffix,
|
||||
Expression, ExpressionList, ExpressionStatement, Function, FunctionAliasBody,
|
||||
FunctionBlockBody, FunctionBody, FunctionEqualsBody, GenericParameters, Identifier,
|
||||
IdentifierExpression, IdentifierOrFqn, LValue, LValueSuffix, ModuleLevelDeclaration,
|
||||
ObjectIndex, Parameter, Parameters, PrimitiveType, ReturnType, StarUseStatement, Statement,
|
||||
SuffixExpression, SuffixOperator, TypeUse, TypedArray, UseStatement, UseStatementIdentifier,
|
||||
UseStatementPrefix, VariableDeclaration,
|
||||
AssignmentStatement, BacktickString, Call, CompilationUnit, ConcreteUseStatement,
|
||||
ConcreteUseStatementSuffix, DString, Expression, ExpressionList, ExpressionStatement, Function,
|
||||
FunctionAliasBody, FunctionBlockBody, FunctionBody, FunctionEqualsBody, GenericParameters,
|
||||
Identifier, IdentifierExpression, IdentifierOrFqn, LValue, LValueSuffix, Literal,
|
||||
ModuleLevelDeclaration, ObjectIndex, Parameter, Parameters, PlatformFunction, PrimitiveType,
|
||||
ReturnType, StarUseStatement, Statement, SuffixExpression, SuffixOperator, TypeUse, TypedArray,
|
||||
UseStatement, UseStatementIdentifier, UseStatementPrefix, VariableDeclaration,
|
||||
};
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol::source_definition::SourceDefinition;
|
||||
@ -153,7 +153,7 @@ fn na_p2_module_level_declaration(
|
||||
na_p2_function(function, symbol_table, diagnostics);
|
||||
}
|
||||
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
|
||||
todo!()
|
||||
na_p2_platform_function(platform_function, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,6 +197,44 @@ fn na_p2_function(
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
fn na_p2_platform_function(
|
||||
platform_function: &mut PlatformFunction,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
// change to this function's scope
|
||||
symbol_table.set_current_scope(*platform_function.scope_id().unwrap());
|
||||
|
||||
// generics
|
||||
na_p2_generic_parameters(platform_function.generics_mut(), symbol_table, diagnostics);
|
||||
|
||||
// parameters
|
||||
let parameter_symbols = na_p2_parameters(
|
||||
platform_function.parameters_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
platform_function
|
||||
.function_symbol_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_parameter_symbols(parameter_symbols);
|
||||
|
||||
// return_type
|
||||
let maybe_return_type_symbol = na_p2_return_type(
|
||||
platform_function.return_type_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
if let Some(return_type_symbol) = maybe_return_type_symbol {
|
||||
platform_function
|
||||
.function_symbol_mut()
|
||||
.unwrap()
|
||||
.borrow_mut()
|
||||
.set_return_type(return_type_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_generic_parameters(
|
||||
generic_parameters: &mut GenericParameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
@ -602,7 +640,7 @@ fn na_p2_expression(
|
||||
na_p2_suffix_expression(suffix, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Literal(literal) => {
|
||||
todo!()
|
||||
na_p2_literal(literal, symbol_table, diagnostics);
|
||||
}
|
||||
Expression::Identifier(identifier_expression) => {
|
||||
na_p2_identifier_expression(identifier_expression, symbol_table, diagnostics);
|
||||
@ -726,3 +764,49 @@ fn na_p2_expression_list(
|
||||
na_p2_expression(expression, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_literal(
|
||||
literal: &mut Literal,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match literal {
|
||||
Literal::DString(d_string) => {
|
||||
na_p2_d_string(d_string, symbol_table, diagnostics);
|
||||
}
|
||||
Literal::BacktickString(backtick_string) => {
|
||||
na_p2_backtick_string(backtick_string, symbol_table, diagnostics);
|
||||
}
|
||||
_ => {
|
||||
// no-op, nothing to check.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_d_string(
|
||||
d_string: &mut DString,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for d_string_expression in d_string.expressions_mut() {
|
||||
na_p2_expression(
|
||||
d_string_expression.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn na_p2_backtick_string(
|
||||
backtick_string: &mut BacktickString,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for d_string_expression in backtick_string.expressions_mut() {
|
||||
na_p2_expression(
|
||||
d_string_expression.expression_mut(),
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::name_analysis::symbol::{ExpressibleSymbol, LVSymbol, Symbol};
|
||||
use crate::name_analysis::symbol_table::fqn_context::FqnContext;
|
||||
use crate::name_analysis::symbol_table::symbol_tree::SymbolTree;
|
||||
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
||||
use crate::name_analysis::util::join_fqn_parts;
|
||||
use scope::Scope;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
@ -132,6 +133,45 @@ impl SymbolTable {
|
||||
as_rc
|
||||
}
|
||||
|
||||
pub fn resolve_global_imports(&mut self) {
|
||||
let global_scope = &self.scopes[0];
|
||||
for concrete_use_symbol in global_scope.concrete_use_symbols() {
|
||||
match self
|
||||
.symbol_tree
|
||||
.find_usable_symbol(concrete_use_symbol.borrow().fqn_parts())
|
||||
{
|
||||
Ok(usable_symbol) => {
|
||||
concrete_use_symbol.borrow_mut().set_resolved_symbol(usable_symbol);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
// panic because this is definitely a compiler/configuration error
|
||||
panic!(
|
||||
"{:?}: Cannot resolve global import {}",
|
||||
symbol_lookup_error,
|
||||
join_fqn_parts(concrete_use_symbol.borrow().fqn_parts())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for star_use_symbol in global_scope.star_use_symbols() {
|
||||
let mut star_use_symbol_ref_mut = star_use_symbol.borrow_mut();
|
||||
match self.symbol_tree.find_all_by_base_fqn(star_use_symbol_ref_mut.fqn_parts()) {
|
||||
Ok(usable_symbols) => {
|
||||
star_use_symbol_ref_mut.set_resolved_symbols(usable_symbols);
|
||||
}
|
||||
Err(symbol_lookup_error) => {
|
||||
// again, panic because this is a compiler/configuration error
|
||||
panic!(
|
||||
"{:?}: Cannot resolve global star import {}::*",
|
||||
symbol_lookup_error,
|
||||
join_fqn_parts(star_use_symbol.borrow().fqn_parts())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_usable_symbols_by_base_fqn(
|
||||
&self,
|
||||
fqn_parts: &[Rc<str>],
|
||||
|
||||
@ -69,6 +69,14 @@ impl Scope {
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn concrete_use_symbols(&self) -> impl Iterator<Item = &Rc<RefCell<ConcreteUseSymbol>>> {
|
||||
self.concrete_use_symbols.values()
|
||||
}
|
||||
|
||||
pub fn star_use_symbols(&self) -> impl Iterator<Item = &Rc<RefCell<StarUseSymbol>>> {
|
||||
self.star_use_symbols.values()
|
||||
}
|
||||
|
||||
pub fn insert_concrete_use_symbol(
|
||||
&mut self,
|
||||
|
||||
@ -81,8 +81,10 @@ impl SymbolTree {
|
||||
panic!("Unable to register module fqn with no parts.")
|
||||
}
|
||||
if fqn_parts.len() == 1 {
|
||||
self.children
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new(fqn_parts[0].as_ref()));
|
||||
if !self.children.contains_key(&fqn_parts[0]) {
|
||||
self.children
|
||||
.insert(fqn_parts[0].clone(), SymbolTree::new(fqn_parts[0].as_ref()));
|
||||
}
|
||||
} else {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get_mut(fqn_parts[0].as_ref()).unwrap();
|
||||
@ -154,12 +156,44 @@ impl SymbolTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_usable_symbol(
|
||||
&self,
|
||||
fqn_parts: &[Rc<str>],
|
||||
) -> Result<UsableSymbol, SymbolLookupError> {
|
||||
match fqn_parts.len() {
|
||||
0 => panic!("Cannot resolve a usable symbol with no fqn part."),
|
||||
1 => self
|
||||
.find_interface(fqn_parts)
|
||||
.map(|interface_symbol| UsableSymbol::Interface(interface_symbol.clone()))
|
||||
.or_else(|| {
|
||||
self.find_class(fqn_parts)
|
||||
.map(|class_symbol| UsableSymbol::Class(class_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
self.find_function(fqn_parts)
|
||||
.map(|function_symbol| UsableSymbol::Function(function_symbol))
|
||||
})
|
||||
.map_or_else(
|
||||
|| Err(SymbolLookupError::NoDefinition),
|
||||
|usable_symbol| Ok(usable_symbol),
|
||||
),
|
||||
_ => {
|
||||
if self.children.contains_key(fqn_parts[0].as_ref()) {
|
||||
let child = self.children.get(fqn_parts[0].as_ref()).unwrap();
|
||||
child.find_usable_symbol(&fqn_parts[1..])
|
||||
} else {
|
||||
Err(SymbolLookupError::NoSuchNamespace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FormatAction<'a> {
|
||||
PrintSymbolTree(&'a SymbolTree),
|
||||
IncreaseIndent,
|
||||
DecreaseIndent
|
||||
DecreaseIndent,
|
||||
}
|
||||
|
||||
impl Display for SymbolTree {
|
||||
@ -168,7 +202,7 @@ impl Display for SymbolTree {
|
||||
let mut indent_writer = IndentWriter::new(0, " ", &mut acc);
|
||||
let mut stack: Vec<FormatAction> = vec![];
|
||||
stack.push(FormatAction::PrintSymbolTree(self));
|
||||
|
||||
|
||||
while let Some(format_action) = stack.pop() {
|
||||
match format_action {
|
||||
FormatAction::PrintSymbolTree(symbol_tree) => {
|
||||
@ -181,7 +215,10 @@ impl Display for SymbolTree {
|
||||
// increase for the first child
|
||||
stack.push(FormatAction::IncreaseIndent);
|
||||
|
||||
indent_writer.writeln_indented(&format!("SymbolTree(debug_name = {})", symbol_tree.debug_name))?;
|
||||
indent_writer.writeln_indented(&format!(
|
||||
"SymbolTree(debug_name = {})",
|
||||
symbol_tree.debug_name
|
||||
))?;
|
||||
|
||||
indent_writer.increase_indent();
|
||||
for interface in symbol_tree.interfaces.values() {
|
||||
@ -203,7 +240,7 @@ impl Display for SymbolTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
writeln!(f, "{}", acc)
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,6 +503,12 @@ PlatformFunction:
|
||||
- identifier
|
||||
- parameters
|
||||
- return_type
|
||||
fields:
|
||||
- function_symbol:
|
||||
kind: FunctionSymbol
|
||||
wrap: rc_ref_cell
|
||||
- scope_id:
|
||||
kind: usize
|
||||
PlatformOperatorFunction:
|
||||
struct:
|
||||
children:
|
||||
|
||||
@ -188,8 +188,8 @@ FullyQualifiedName = {
|
||||
}
|
||||
|
||||
IdentifierOrFqn = {
|
||||
Identifier
|
||||
| FullyQualifiedName
|
||||
FullyQualifiedName
|
||||
| Identifier
|
||||
}
|
||||
|
||||
// Common lists
|
||||
|
||||
Loading…
Reference in New Issue
Block a user