Resolve local variables.
This commit is contained in:
parent
dd249dd5bd
commit
34fae6ccca
@ -7,8 +7,8 @@ fn getWorlds() -> List<World> = [
|
||||
]
|
||||
|
||||
fn findWorldByColor(worlds: List<World>, color: String) -> String
|
||||
worlds.find { it.color == color }
|
||||
.map { it.name }
|
||||
worlds.find { it -> it.color == color }
|
||||
.map { it -> it.name }
|
||||
.expect "No world has the given color ${color}"
|
||||
end
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ use crate::name_analysis::symbol::type_symbol::{
|
||||
};
|
||||
use crate::name_analysis::symbol::use_symbol::{ConcreteUseSymbol, StarUseSymbol};
|
||||
use crate::name_analysis::symbol::variable_symbol::VariableSymbol;
|
||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolLookupError, SymbolTable};
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use std::range::Range;
|
||||
|
||||
@ -56,6 +56,29 @@ fn handle_insert_error(
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_lookup_error(
|
||||
err: SymbolLookupError,
|
||||
error_symbol_name: &str,
|
||||
error_file_id: usize,
|
||||
error_range: Range<usize>,
|
||||
symbol_types: &str,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_node_children<'a>(
|
||||
node: &'a dyn AstNode<'a>,
|
||||
symbol_table: &mut SymbolTable,
|
||||
@ -244,11 +267,8 @@ fn gather_node<'a>(
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
AstNodeRef::LValue(l_value) => {
|
||||
gather_node_children(l_value, symbol_table, fqn_context, scope_table, diagnostics);
|
||||
}
|
||||
AstNodeRef::VariableUse(variable_use) => {
|
||||
gather_variable_use(variable_use, symbol_table, scope_table);
|
||||
gather_variable_use(variable_use, symbol_table, diagnostics);
|
||||
}
|
||||
AstNodeRef::TernaryExpression(ternary_expression) => {
|
||||
gather_ternary_expression(
|
||||
@ -1234,9 +1254,21 @@ fn gather_for_statement<'a>(
|
||||
fn gather_variable_use<'a>(
|
||||
variable_use: &'a VariableUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
scope_table: &mut ScopeTable<'a>,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
scope_table.insert_variable_use_scope(variable_use, symbol_table.current_scope_id());
|
||||
if let Err(lookup_error) = symbol_table.lookup_addressable_by_identifier(
|
||||
variable_use.identifier().name(),
|
||||
symbol_table.current_scope_id(),
|
||||
) {
|
||||
handle_lookup_error(
|
||||
lookup_error,
|
||||
variable_use.identifier().name(),
|
||||
variable_use.identifier().file_id(),
|
||||
variable_use.identifier().range(),
|
||||
"Variable",
|
||||
diagnostics,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_ternary_expression<'a>(
|
||||
|
||||
@ -45,8 +45,11 @@ impl SymbolTable {
|
||||
|
||||
pub fn push_scope(&mut self, debug_name: &str) {
|
||||
let id = self.scopes.len();
|
||||
self.scopes
|
||||
.push(Scope::new(Some(self.current_scope_id), id, debug_name.to_string()));
|
||||
self.scopes.push(Scope::new(
|
||||
Some(self.current_scope_id),
|
||||
id,
|
||||
debug_name.to_string(),
|
||||
));
|
||||
self.current_scope_id = id;
|
||||
}
|
||||
|
||||
@ -316,7 +319,61 @@ impl SymbolTable {
|
||||
Some(&self.scopes[parent_id])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
|
||||
fn lookup_addressable_in_scope_by_identifier(
|
||||
scope: &Scope,
|
||||
identifier: &str,
|
||||
) -> Option<Symbol> {
|
||||
scope
|
||||
.variable_symbols()
|
||||
.get(identifier)
|
||||
.map(|variable_symbol| Symbol::Variable(variable_symbol.clone()))
|
||||
.or_else(|| {
|
||||
scope
|
||||
.parameter_symbols()
|
||||
.get(identifier)
|
||||
.map(|parameter_symbol| Symbol::Parameter(parameter_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.class_member_symbols()
|
||||
.get(identifier)
|
||||
.map(|class_member_symbol| Symbol::ClassMember(class_member_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.function_symbols()
|
||||
.get(identifier)
|
||||
.map(|function_symbol| Symbol::Function(function_symbol.clone()))
|
||||
})
|
||||
.or_else(|| {
|
||||
scope
|
||||
.type_symbols()
|
||||
.get(identifier)
|
||||
.map(|type_symbol| Symbol::Type(type_symbol.clone()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lookup_addressable_by_identifier(
|
||||
&self,
|
||||
identifier: &str,
|
||||
scope_id: usize,
|
||||
) -> Result<Symbol, SymbolLookupError> {
|
||||
let mut scope_opt = Some(&self.scopes[scope_id]);
|
||||
while let Some(scope) = scope_opt {
|
||||
if let Some(symbol) = Self::lookup_addressable_in_scope_by_identifier(scope, identifier)
|
||||
{
|
||||
return Ok(symbol);
|
||||
}
|
||||
scope_opt = if let Some(parent_id) = scope.parent() {
|
||||
Some(&self.scopes[parent_id])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user