use crate::functions::find_binding_local_statement::find_binding_local_statement;
use crate::functions::find_expr_or_local_at_position::find_expr_or_local_at_position;
use crate::functions::find_scope_at_position::find_scope_at_position;
use crate::records::binding::Binding;
use crate::records::module::Module;
use crate::records::source_module::SourceModule;
use crate::records::symbol::Symbol;
use luaur_ast::records::ast_expr_global::AstExprGlobal;
use luaur_ast::records::ast_expr_local::AstExprLocal;
use luaur_ast::records::ast_node::AstNode;
use luaur_ast::records::position::Position;
use luaur_ast::rtti::ast_node_as;
pub fn find_binding_at_position(
module: &Module,
source: &SourceModule,
pos: Position,
) -> Option<Binding> {
let expr_or_local = find_expr_or_local_at_position(source, pos);
let name = if !expr_or_local.expr.is_null() {
unsafe {
let global = ast_node_as::<AstExprGlobal>(expr_or_local.expr as *mut AstNode);
if !global.is_null() {
Symbol::symbol_ast_name((*global).name)
} else {
let local = ast_node_as::<AstExprLocal>(expr_or_local.expr as *mut AstNode);
if !local.is_null() {
Symbol::symbol_ast_local((*local).local)
} else {
return None;
}
}
}
} else if !expr_or_local.local.is_null() {
Symbol::symbol_ast_local(expr_or_local.local)
} else {
return None;
};
let mut current_scope = find_scope_at_position(module, pos);
while let Some(ref scope) = current_scope {
if let Some(binding) = scope.bindings.get(&name) {
if binding.location.begin <= pos {
if let Some(binding_statement) = find_binding_local_statement(source, binding) {
let stmt_location = unsafe { &*binding_statement }.base.base.location;
if stmt_location.contains(pos) {
current_scope = scope.parent.clone();
continue;
}
}
return Some(binding.clone());
}
}
current_scope = scope.parent.clone();
}
None
}