Skip to main content

harn_parser/lexical/
mutations.rs

1//! Assignment summaries preserve the lexical owner's shadowing rules.
2
3use super::*;
4
5/// Names reassigned by a nested callable, including unknown outer parameters.
6pub fn nested_callable_reassigned_names(
7    body: &[SNode],
8    match_patterns: &MatchPatternCatalog,
9) -> Vec<String> {
10    let mut analysis = LexicalAnalysis::new(match_patterns);
11    analysis.walk_body(body, Vec::new(), false, BindingOwner::Current);
12    analysis.reassigned.into_iter().collect()
13}
14
15/// Captured values whose contents may change when a nested callable executes.
16pub fn nested_callable_value_write_names(
17    body: &[SNode],
18    match_patterns: &MatchPatternCatalog,
19) -> Vec<String> {
20    let mut analysis = LexicalAnalysis::new(match_patterns);
21    analysis.record_property_writes = true;
22    analysis.walk_body(body, Vec::new(), false, BindingOwner::Current);
23    analysis.reassigned.into_iter().collect()
24}
25
26/// Values outside this block that any assignment may change. A declaration
27/// inside the block shadows an outer value; property writes still mutate their
28/// receiver. Nested callables are conservative because their effects may escape.
29pub fn outer_value_write_names(
30    body: &[SNode],
31    match_patterns: &MatchPatternCatalog,
32) -> Vec<String> {
33    let mut analysis = LexicalAnalysis::new(match_patterns);
34    analysis.record_property_writes = true;
35    analysis.walk_body(body, Vec::new(), true, BindingOwner::Nested);
36    analysis.reassigned.into_iter().collect()
37}
38
39pub(super) fn assignment_root_name(target: &SNode) -> Option<&str> {
40    match &target.node {
41        Node::Identifier(name) => Some(name),
42        Node::PropertyAccess { object, .. }
43        | Node::OptionalPropertyAccess { object, .. }
44        | Node::SubscriptAccess { object, .. }
45        | Node::OptionalSubscriptAccess { object, .. } => assignment_root_name(object),
46        _ => None,
47    }
48}