1use crate::symbols::VarId;
2use std::collections::{BTreeMap, HashMap};
3
4#[derive(Debug, Clone, Default)]
5pub struct Scope {
6 vars: HashMap<String, VarId>,
7}
8
9impl Scope {
10 pub fn new() -> Self {
11 Self {
12 vars: HashMap::new(),
13 }
14 }
15
16 pub fn declare(&mut self, name: String, id: VarId) {
17 self.vars.insert(name, id);
18 }
19
20 pub fn resolve(&self, name: &str) -> Option<VarId> {
21 self.vars.get(name).copied()
22 }
23
24 pub fn iter(&self) -> impl Iterator<Item = (&String, &VarId)> {
25 self.vars.iter()
26 }
27
28 pub fn clear(&mut self) {
29 self.vars.clear();
30 }
31
32 pub fn contains(&self, name: &str) -> bool {
33 self.vars.contains_key(name)
34 }
35}
36
37#[derive(Debug, Clone)]
38pub struct ScopeStack {
39 scopes: Vec<Scope>,
40}
41
42impl Default for ScopeStack {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl ScopeStack {
49 pub fn new() -> Self {
50 Self {
51 scopes: vec![Scope::new()],
52 }
53 }
54
55 pub fn push(&mut self) {
56 self.scopes.push(Scope::new());
57 }
58
59 pub fn pop(&mut self) {
60 if self.scopes.len() > 1 {
61 self.scopes.pop();
62 } else if let Some(scope) = self.scopes.last_mut() {
63 scope.clear();
64 }
65 }
66
67 pub fn clear(&mut self) {
68 self.scopes.clear();
69 self.scopes.push(Scope::new());
70 }
71
72 pub fn declare(&mut self, name: String, id: VarId) {
73 if self.scopes.is_empty() {
74 self.scopes.push(Scope::new());
75 }
76
77 if let Some(scope) = self.scopes.last_mut() {
78 scope.declare(name, id);
79 }
80 }
81
82 pub fn resolve(&self, name: &str) -> Option<VarId> {
83 for scope in self.scopes.iter().rev() {
84 if let Some(id) = scope.resolve(name) {
85 return Some(id);
86 }
87 }
88 None
89 }
90
91 pub fn contains_in_current_scope(&self, name: &str) -> bool {
92 self.scopes
93 .last()
94 .map(|scope| scope.contains(name))
95 .unwrap_or(false)
96 }
97
98 pub fn visible_bindings(&self) -> BTreeMap<String, VarId> {
99 let mut out = BTreeMap::new();
100
101 for scope in &self.scopes {
102 for (name, id) in scope.iter() {
103 out.insert(name.clone(), *id);
104 }
105 }
106
107 out
108 }
109}