arrow_parser/
lifetime_analysis.rs

1use crate::ast::Expression;
2use crate::ast::LiteralTemplatePart;
3use crate::ast::Module;
4use crate::ast::ModuleItem;
5use crate::ast::Node;
6use crate::ast::Statement;
7use crate::symbol::Scope;
8use crate::symbol::ScopeType;
9
10// - TODO Detect usages of variables physically before their usage, including in nested closures. This is mostly a lint, and doesn't actually affect program correctness.
11// - We can't run this analysis during parsing due to forward references, and we can't run this analysis during compilation due to needing a full pass to detect usages in nested closures before we compile their ancestor code.
12
13pub struct LifetimeAnalyser {}
14
15impl LifetimeAnalyser {
16  fn process_variable(&mut self, scope: &Scope, name: &str) {
17    if let Some((decl_scope, symbol)) = scope.find_symbol_declaration(name) {
18      // Name refers to non-host variable.
19      if let Some(decl_closure) = decl_scope.find_nearest_closure() {
20        // The variable is inside a closure (might be in a nested block, but isn't a module variable).
21        if let Some(usage_closure) = scope.find_nearest_closure() {
22          // We are currently in a closure (might be in a nested block).
23          if decl_closure != usage_closure {
24            // We are using a variable in a different closure.
25            decl_scope.borrow_mut().boxed_var_decls.insert(symbol);
26            let mut cur = usage_closure;
27            while cur != decl_scope {
28              if cur.typ == ScopeType::Closure {
29                cur.borrow_mut().boxed_var_captures.insert(symbol);
30              };
31              cur = cur.parent().unwrap();
32            }
33          };
34        };
35      };
36    };
37  }
38
39  fn analyse_expression(&mut self, expr: &Node<Expression>) {
40    match expr.stx.as_ref() {
41      Expression::Binary { left, right, .. } => {
42        self.analyse_expression(left);
43        self.analyse_expression(right);
44      }
45      Expression::BindMethod { arguments, .. } => {
46        for arg in arguments {
47          self.analyse_expression(arg);
48        }
49      }
50      Expression::Block { statements, result } => {
51        for stmt in statements {
52          self.analyse_statement(stmt);
53        }
54        if let Some(result) = result {
55          self.analyse_expression(result);
56        };
57      }
58      Expression::CallMethod {
59        object, arguments, ..
60      } => {
61        self.analyse_expression(object);
62        for arg in arguments {
63          self.analyse_expression(arg);
64        }
65      }
66      Expression::CallValue {
67        callee, arguments, ..
68      } => {
69        self.analyse_expression(callee);
70        for arg in arguments {
71          self.analyse_expression(arg);
72        }
73      }
74      Expression::Cast { value, .. } => {
75        self.analyse_expression(value);
76      }
77      Expression::Field { object, .. } => {
78        self.analyse_expression(object);
79      }
80      Expression::Index { object, index, .. } => {
81        self.analyse_expression(object);
82        self.analyse_expression(index);
83      }
84      Expression::If {
85        condition,
86        consequent,
87        alternate,
88      } => {
89        self.analyse_expression(condition);
90        self.analyse_expression(consequent);
91        if let Some(alternate) = alternate {
92          self.analyse_expression(alternate);
93        };
94      }
95      Expression::Closure { body, .. } => {
96        self.analyse_expression(body);
97      }
98      Expression::LiteralArray { entries } => {
99        for ent in entries {
100          self.analyse_expression(ent);
101        }
102      }
103      Expression::LiteralBoolean { .. } => {}
104      Expression::LiteralFloat { .. } => {}
105      Expression::LiteralInt { .. } => {}
106      Expression::LiteralNone { .. } => {}
107      Expression::LiteralObject { fields } => {
108        for (_, value) in fields {
109          self.analyse_expression(value);
110        }
111      }
112      Expression::LiteralTemplateExpr { parts } => {
113        for part in parts {
114          match part {
115            LiteralTemplatePart::Substitution(v) => {
116              self.analyse_expression(v);
117            }
118            LiteralTemplatePart::String(_) => {}
119          };
120        }
121      }
122      Expression::Unary { operand, .. } => {
123        self.analyse_expression(operand);
124      }
125      Expression::Var { name } => {
126        self.process_variable(&expr.scope, name);
127      }
128    }
129  }
130
131  fn analyse_statement(&mut self, stmt: &Node<Statement>) {
132    match stmt.stx.as_ref() {
133      Statement::Break => {}
134      Statement::Continue => {}
135      Statement::Expression { expression } => {
136        self.analyse_expression(expression);
137      }
138      Statement::FieldAssign { object, value, .. } => {
139        self.analyse_expression(object);
140        self.analyse_expression(value);
141      }
142      Statement::For { iterable, body, .. } => {
143        self.analyse_expression(iterable);
144        self.analyse_expression(body);
145      }
146      Statement::IndexAssign {
147        object,
148        index,
149        value,
150        ..
151      } => {
152        self.analyse_expression(object);
153        self.analyse_expression(index);
154        self.analyse_expression(value);
155      }
156      Statement::Let { value, .. } => {
157        self.analyse_expression(value);
158      }
159      Statement::Loop { body } => {
160        self.analyse_expression(body);
161      }
162      Statement::Return { value } => {
163        if let Some(value) = value {
164          self.analyse_expression(value);
165        };
166      }
167      Statement::VarAssign { variable, value } => {
168        self.analyse_expression(value);
169        self.process_variable(&stmt.scope, &variable);
170      }
171    };
172  }
173
174  fn analyse_module_item(&mut self, item: &Node<ModuleItem>) {
175    match item.stx.as_ref() {
176      ModuleItem::Impl { methods, .. } => {
177        for (_, method) in methods {
178          self.analyse_expression(method);
179        }
180      }
181      ModuleItem::Statement { statement } => {
182        self.analyse_statement(statement);
183      }
184    };
185  }
186
187  pub fn analyse_lifetimes(&mut self, module: &Module) {
188    for item in module.items.iter() {
189      self.analyse_module_item(item);
190    }
191  }
192}