luaur_analysis/records/
find_expr_or_local.rs1use luaur_ast::records::ast_expr::AstExpr;
2use luaur_ast::records::ast_expr_function::AstExprFunction;
3use luaur_ast::records::ast_local::AstLocal;
4use luaur_ast::records::ast_node::AstNode;
5use luaur_ast::records::ast_stat_block::AstStatBlock;
6use luaur_ast::records::ast_stat_for::AstStatFor;
7use luaur_ast::records::ast_stat_for_in::AstStatForIn;
8use luaur_ast::records::ast_stat_local::AstStatLocal;
9use luaur_ast::records::ast_stat_local_function::AstStatLocalFunction;
10use luaur_ast::records::ast_visitor::AstVisitor;
11use luaur_ast::records::location::Location;
12use luaur_ast::records::position::Position;
13use luaur_ast::visit;
14
15use crate::records::expr_or_local::ExprOrLocal;
16
17#[derive(Debug, Clone)]
18pub struct FindExprOrLocal {
19 pub(crate) pos: Position,
20 pub(crate) result: ExprOrLocal,
21}
22
23impl FindExprOrLocal {
24 pub fn new(pos: Position) -> Self {
25 Self {
26 pos,
27 result: ExprOrLocal {
28 expr: core::ptr::null_mut(),
29 local: core::ptr::null_mut(),
30 },
31 }
32 }
33
34 pub(crate) fn is_closer_match(&self, new_location: Location) -> bool {
35 let current = self.result.get_location();
36 new_location.contains(self.pos)
37 && (current.is_none() || current.map_or(false, |c| c.encloses(&new_location)))
38 }
39
40 fn visit_local(&mut self, local: *mut AstLocal) -> bool {
41 let location = unsafe { (*local).location };
42 if self.is_closer_match(location) {
43 self.result.set_local(local);
44 true
45 } else {
46 false
47 }
48 }
49}
50
51impl AstVisitor for FindExprOrLocal {
52 fn visit_stat_block(&mut self, node: *mut core::ffi::c_void) -> bool {
53 let block = node as *mut AstStatBlock;
54 unsafe {
55 for stat in (*block).body.iter() {
56 let stat = *stat;
57 let stat_node = stat as *mut AstNode;
58 if (*stat_node).location.end <= self.pos {
59 continue;
60 }
61 if (*stat_node).location.begin > self.pos {
62 break;
63 }
64 visit::ast_stat_visit(stat, self);
65 }
66 }
67 false
68 }
69
70 fn visit_expr(&mut self, node: *mut core::ffi::c_void) -> bool {
71 let expr = node as *mut AstExpr;
72 let location = unsafe { (*expr).base.location };
73 if self.is_closer_match(location) {
74 self.result.set_expr(expr);
75 true
76 } else {
77 false
78 }
79 }
80
81 fn visit_stat_local_function(&mut self, node: *mut core::ffi::c_void) -> bool {
82 let func = node as *mut AstStatLocalFunction;
83 unsafe {
84 self.visit_local((*func).name);
85 }
86 true
87 }
88
89 fn visit_stat_local(&mut self, node: *mut core::ffi::c_void) -> bool {
90 let stat = node as *mut AstStatLocal;
91 unsafe {
92 for i in 0..(*stat).vars.size {
93 let local = unsafe { *((*stat).vars.data.add(i as usize)) };
94 self.visit_local(local);
95 }
96 }
97 true
98 }
99
100 fn visit_expr_function(&mut self, node: *mut core::ffi::c_void) -> bool {
101 let func = node as *mut AstExprFunction;
102 unsafe {
103 for i in 0..(*func).args.size {
104 let local = unsafe { *((*func).args.data.add(i as usize)) };
105 self.visit_local(local);
106 }
107 }
108 self.visit_expr(node)
109 }
110
111 fn visit_stat_for(&mut self, node: *mut core::ffi::c_void) -> bool {
112 let stat = node as *mut AstStatFor;
113 unsafe {
114 self.visit_local((*stat).var);
115 }
116 true
117 }
118
119 fn visit_stat_for_in(&mut self, node: *mut core::ffi::c_void) -> bool {
120 let stat = node as *mut AstStatForIn;
121 unsafe {
122 for i in 0..(*stat).vars.size {
123 let local = unsafe { *((*stat).vars.data.add(i as usize)) };
124 self.visit_local(local);
125 }
126 }
127 true
128 }
129}