swamp_script_analyzer/
variable.rs1use crate::err::{Error, ErrorKind};
6use crate::{Analyzer, BlockScopeMode};
7use std::rc::Rc;
8use swamp_script_semantic::{
9 Expression, ExpressionKind, MutOrImmutableExpression, Node, Type, Variable, VariableRef,
10};
11use tracing::error;
12
13impl Analyzer<'_> {
14 fn try_find_local_variable(&self, node: &Node) -> Option<&VariableRef> {
15 let current_scope = self
16 .scope
17 .block_scope_stack
18 .iter()
19 .last()
20 .expect("no scope stack available");
21
22 let variable_text = self.get_text_resolved(node).to_string();
23
24 current_scope.variables.get(&variable_text)
25 }
26
27 #[allow(unused)]
28 pub(crate) fn find_variable(
29 &self,
30 variable: &swamp_script_ast::Variable,
31 ) -> Result<VariableRef, Error> {
32 self.try_find_variable(&variable.name).map_or_else(
33 || Err(self.create_err(ErrorKind::UnknownVariable, &variable.name)),
34 Ok,
35 )
36 }
37
38 pub(crate) fn try_find_variable(&self, node: &swamp_script_ast::Node) -> Option<VariableRef> {
39 let variable_text = self.get_text(node);
40
41 for scope in self.scope.block_scope_stack.iter().rev() {
42 if let Some(value) = scope.variables.get(&variable_text.to_string()) {
43 return Some(value.clone());
44 }
45 if scope.mode == BlockScopeMode::Closed {
46 break;
47 }
48 }
49
50 None
51 }
52
53 pub(crate) fn set_or_overwrite_variable_with_type(
54 &mut self,
55 variable: &swamp_script_ast::Variable,
56 variable_type_ref: &Type,
57 ) -> Result<(VariableRef, bool), Error> {
58 if let Some(existing_variable) = self.try_find_variable(&variable.name) {
59 if !&existing_variable
61 .resolved_type
62 .assignable_type(variable_type_ref)
63 {
64 return Err(
65 self.create_err(ErrorKind::OverwriteVariableWithAnotherType, &variable.name)
66 );
67 }
68
69 if !existing_variable.is_mutable() {
71 return Err(
72 self.create_err(ErrorKind::CanOnlyOverwriteVariableWithMut, &variable.name)
73 );
74 }
75
76 return Ok((existing_variable, true));
77 }
78
79 let scope_index = self.scope.block_scope_stack.len() - 1;
81 let name = self.to_node(&variable.name);
82 let mutable_node = self.to_node_option(Option::from(&variable.is_mutable));
83 let variable_name_str = self.get_text_resolved(&name).to_string();
84
85 let variables = &mut self
86 .scope
87 .block_scope_stack
88 .last_mut()
89 .expect("block scope should have at least one scope")
90 .variables;
91 let variable_index = variables.len();
92
93 let resolved_variable = Variable {
94 name,
95 resolved_type: variable_type_ref.clone(),
96 mutable_node,
97 scope_index,
98 variable_index,
99 };
100
101 let variable_ref = Rc::new(resolved_variable);
102
103 {
104 variables
105 .insert(variable_name_str, variable_ref.clone())
106 .expect("should have checked earlier for variable");
107 }
108
109 Ok((variable_ref, false))
110 }
111 pub(crate) fn create_local_variable(
112 &mut self,
113 variable: &swamp_script_ast::Node,
114 is_mutable: Option<&swamp_script_ast::Node>,
115 variable_type_ref: &Type,
116 ) -> Result<VariableRef, Error> {
117 if variable_type_ref == &Type::Unit {
118 let debug_text = self.get_text(variable);
119 error!(
120 ?debug_text,
121 "panic, tries to create a local variable as a unit"
122 );
123 }
124 assert_ne!(*variable_type_ref, Type::Unit);
125 self.create_local_variable_resolved(
126 &self.to_node(variable),
127 Option::from(&self.to_node_option(is_mutable)),
128 variable_type_ref,
129 )
130 }
131
132 pub(crate) fn create_variable(
133 &mut self,
134 variable: &swamp_script_ast::Variable,
135 variable_type_ref: &Type,
136 ) -> Result<VariableRef, Error> {
137 self.create_local_variable(
138 &variable.name,
139 Option::from(&variable.is_mutable),
140 variable_type_ref,
141 )
142 }
143
144 pub(crate) fn create_local_variable_resolved(
145 &mut self,
146 variable: &Node,
147 is_mutable: Option<&Node>,
148 variable_type_ref: &Type,
149 ) -> Result<VariableRef, Error> {
150 if let Some(_existing_variable) = self.try_find_local_variable(variable) {
151 return Err(
152 self.create_err_resolved(ErrorKind::OverwriteVariableNotAllowedHere, variable)
153 );
154 }
155 let variable_str = self.get_text_resolved(variable).to_string();
156
157 let scope_index = self.scope.block_scope_stack.len() - 1;
158
159 let variables = &mut self
160 .scope
161 .block_scope_stack
162 .last_mut()
163 .expect("block scope should have at least one scope")
164 .variables;
165
166 let resolved_variable = Variable {
167 name: variable.clone(),
168 resolved_type: variable_type_ref.clone(),
169 mutable_node: is_mutable.cloned(),
170 scope_index,
171 variable_index: variables.len(),
172 };
173
174 let variable_ref = Rc::new(resolved_variable);
175
176 let should_insert_in_scope = !variable_str.starts_with('_');
177 if !should_insert_in_scope && is_mutable.is_some() {
178 return Err(self.create_err_resolved(ErrorKind::UnusedVariablesCanNotBeMut, variable));
179 }
180 if should_insert_in_scope {
181 variables
182 .insert(variable_str, variable_ref.clone())
183 .expect("should have checked earlier for variable");
184 }
185
186 Ok(variable_ref)
187 }
188
189 pub(crate) fn create_local_variable_generated(
190 &mut self,
191 variable_str: &str,
192 is_mutable: bool,
193 variable_type_ref: &Type,
194 ) -> Result<VariableRef, Error> {
195 let scope_index = self.scope.block_scope_stack.len() - 1;
196
197 let variables = &mut self
198 .scope
199 .block_scope_stack
200 .last_mut()
201 .expect("block scope should have at least one scope")
202 .variables;
203
204 let resolved_variable = Variable {
205 name: Node::default(),
206 resolved_type: variable_type_ref.clone(),
207 mutable_node: if is_mutable {
208 Some(Node::default())
209 } else {
210 None
211 },
212 scope_index,
213 variable_index: variables.len(),
214 };
215
216 let variable_ref = Rc::new(resolved_variable);
217
218 variables
219 .insert(variable_str.to_string(), variable_ref.clone())
220 .expect("should have checked earlier for variable");
221
222 Ok(variable_ref)
223 }
224
225 pub(crate) fn create_variable_binding_for_with(
226 &mut self,
227 ast_variable: &swamp_script_ast::Variable,
228 converted_expression: MutOrImmutableExpression,
229 ) -> Result<Expression, Error> {
230 let expression_type = converted_expression.ty().clone();
231 let (variable_ref, _is_reassignment) =
232 self.set_or_overwrite_variable_with_type(ast_variable, &expression_type)?;
233 let expr_kind =
234 ExpressionKind::VariableDefinition(variable_ref, Box::from(converted_expression));
235
236 let expr = self.create_expr(expr_kind, expression_type, &ast_variable.name);
237 Ok(expr)
239 }
240}