arrow_parser/
symbol.rs

1use rustc_hash::FxHashMap;
2use rustc_hash::FxHashSet;
3use serde::Deserialize;
4use serde::Serialize;
5use std::cell::Cell;
6use std::cell::RefCell;
7use std::cell::RefMut;
8use std::rc::Rc;
9
10#[derive(Clone, Default)]
11pub struct SymbolIdGenerator(Rc<Cell<usize>>);
12
13impl SymbolIdGenerator {
14  pub fn next(&self) -> usize {
15    let id = self.0.get();
16    self.0.set(id + 1);
17    id
18  }
19}
20
21#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
22pub struct Symbol {
23  pub id: usize, // Variable names aren't good enough; they can be shadowed, redeclared, etc. We want something to uniquely identify every declared variable within a program.
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
27pub enum ScopeType {
28  Module,
29  Closure,
30  Block,
31}
32
33#[derive(Default)]
34pub struct ScopeData {
35  parent: Option<Scope>,
36  pub symbols: FxHashMap<String, Symbol>,
37  pub boxed_var_decls: FxHashSet<Symbol>, // Used on closure and block scope types. These variables must allocate a new box every time they reach their declaration. Entries should also exist as keys in `symbols`.
38  pub boxed_var_captures: FxHashSet<Symbol>, // Used only on closure scope types. Before entering the closure associated with this scope, capture these boxes from the present scope.
39}
40
41#[derive(Clone)]
42pub struct Scope {
43  pub typ: ScopeType,
44  symbol_id_generator: SymbolIdGenerator,
45  data: Rc<RefCell<ScopeData>>,
46}
47
48impl Scope {
49  pub fn new(typ: ScopeType) -> Self {
50    Self {
51      typ,
52      data: Default::default(),
53      symbol_id_generator: Default::default(),
54    }
55  }
56
57  pub fn new_child(&self, typ: ScopeType) -> Self {
58    Self {
59      typ,
60      symbol_id_generator: self.symbol_id_generator.clone(),
61      data: Rc::new(RefCell::new(ScopeData {
62        parent: Some(self.clone()),
63        ..Default::default()
64      })),
65    }
66  }
67
68  pub fn add_symbol(&self, name: String) -> bool {
69    self
70      .data
71      .borrow_mut()
72      .symbols
73      .insert(name, Symbol {
74        id: self.symbol_id_generator.next(),
75      })
76      .is_none()
77  }
78
79  pub fn has_symbol(&self, name: &str) -> bool {
80    self.data.borrow().symbols.contains_key(name)
81  }
82
83  pub fn get_symbol(&self, name: &str) -> Symbol {
84    self.data.borrow().symbols.get(name).unwrap().clone()
85  }
86
87  pub fn declaration_is_boxed(&self, symbol: Symbol) -> bool {
88    self.data.borrow().boxed_var_decls.contains(&symbol)
89  }
90
91  pub fn captures_box_of(&self, symbol: Symbol) -> bool {
92    self.data.borrow().boxed_var_captures.contains(&symbol)
93  }
94
95  pub fn borrow(&self) -> RefMut<ScopeData> {
96    self.data.borrow_mut()
97  }
98
99  pub fn borrow_mut(&self) -> RefMut<ScopeData> {
100    self.data.borrow_mut()
101  }
102
103  pub fn find_symbol_declaration(&self, name: &str) -> Option<(Scope, Symbol)> {
104    let mut cur = Some(self.clone());
105    while let Some(scope) = cur {
106      if let Some(symbol) = scope.data.borrow_mut().symbols.get(name) {
107        return Some((scope.clone(), *symbol));
108      };
109      cur = scope.parent();
110    }
111    None
112  }
113
114  pub fn find_nearest_scope<P: Fn(ScopeType) -> bool>(&self, pred: P) -> Option<Scope> {
115    let mut cur = Some(self.clone());
116    while let Some(scope) = cur {
117      if pred(scope.typ) {
118        return Some(scope.clone());
119      };
120      cur = scope.parent();
121    }
122    None
123  }
124
125  pub fn find_nearest_closure(&self) -> Option<Scope> {
126    self.find_nearest_scope(|t| t == ScopeType::Closure)
127  }
128
129  pub fn parent(&self) -> Option<Scope> {
130    self.data.borrow().parent.clone()
131  }
132}
133
134impl PartialEq for Scope {
135  fn eq(&self, other: &Self) -> bool {
136    Rc::ptr_eq(&self.data, &other.data)
137  }
138}
139
140impl Eq for Scope {}