y_lang/typechecker/
typescope.rs1use std::{cell::RefCell, collections::HashMap, rc::Rc};
2
3use super::{error::TypeError, variabletype::VariableType};
4
5#[derive(Debug, Clone)]
6pub struct Variable {
7 pub variable_type: VariableType,
8 pub is_mutable: bool,
9}
10
11type ScopeFrame = HashMap<String, Variable>;
12
13type ScopeFrameReference = Rc<RefCell<ScopeFrame>>;
14
15#[derive(Default, Debug, Clone)]
16pub struct TypeScope {
17 scope_stack: Vec<ScopeFrameReference>,
18}
19
20impl PartialEq for TypeScope {
21 fn eq(&self, _: &Self) -> bool {
22 true
23 }
24}
25
26impl Eq for TypeScope {}
27
28impl TypeScope {
29 pub fn find(&self, name: &str) -> Option<VariableType> {
31 let mut scopes = self.scope_stack.clone();
32 scopes.reverse();
33 for scope in scopes {
34 if let Some(variable) = scope.borrow().get(name) {
35 return Some(variable.variable_type.clone());
36 }
37 }
38
39 None
40 }
41
42 pub fn is_mutable(&self, name: &str) -> bool {
43 for (index, scope) in self.scope_stack.iter().rev().enumerate() {
44 if let Some(Variable { is_mutable, .. }) = scope.borrow().get(name) {
45 if *is_mutable || index == 0 {
46 return true;
47 }
48 }
49 }
50
51 false
52 }
53
54 pub fn contains(&self, name: &str) -> bool {
56 let mut scopes = self.scope_stack.clone();
57 scopes.reverse();
58 for scope in &scopes {
59 if scope.borrow().contains_key(name) {
60 return true;
61 }
62 }
63
64 false
65 }
66
67 pub fn contains_in_current_scope(&self, name: &str) -> bool {
69 let Some(last) = self.scope_stack.last() else {
70 return false;
71 };
72 return last.borrow().contains_key(name);
73 }
74
75 pub fn push(&mut self) {
77 self.scope_stack.push(Rc::new(RefCell::new(HashMap::new())))
78 }
79
80 pub fn pop(&mut self) {
82 self.scope_stack.pop();
83 }
84
85 pub fn set(&mut self, name: &str, value: VariableType, is_mutable: bool) {
87 if let Some(scope) = self.scope_stack.last_mut() {
88 let variable = Variable {
89 variable_type: value,
90 is_mutable,
91 };
92 scope.borrow_mut().insert(name.to_owned(), variable);
93 }
94 }
95
96 pub fn update(
98 &mut self,
99 name: &str,
100 value: VariableType,
101 position: &(String, usize, usize),
102 ) -> Result<(), TypeError> {
103 let mut scopes = self.scope_stack.clone();
104 scopes.reverse();
105
106 for scope in &mut scopes {
107 let mut scope = scope.borrow_mut();
108 if let Some(old_variable) = scope.get(name) {
109 let old_type = &old_variable.variable_type;
110 if old_type != &value {
111 return Err(TypeError {
112 message: format!(
113 "Could not assign variable '{name}' with type '{old_type}' a value of type '{value}'"
114 ),
115 position: position.to_owned(),
116 });
117 }
118 let mut new_variable = old_variable.clone();
119 new_variable.variable_type = value;
120 scope.insert(name.to_owned(), new_variable);
121
122 break;
123 }
124 }
125
126 scopes.reverse();
127 self.scope_stack = scopes;
128
129 Ok(())
130 }
131
132 pub fn flatten(&self) -> HashMap<String, Variable> {
133 let mut entries = HashMap::default();
134
135 for scope in &self.scope_stack {
136 let scope = scope.borrow();
137
138 for (key, value) in scope.iter() {
139 entries.insert(key.to_owned(), value.to_owned());
140 }
141 }
142
143 entries
144 }
145}
146
147pub fn setup_scope() -> TypeScope {
148 let mut scope = TypeScope::default();
149
150 scope.push();
151
152 scope
153}