1use codemap::{Span, Spanned};
2
3use crate::{
4 ast::{AstForwardRule, Configuration, ConfiguredValue, Mixin},
5 builtin::modules::{ForwardedModule, Module, ModuleScope, Modules, ShadowedModule},
6 common::Identifier,
7 error::SassResult,
8 selector::ExtensionStore,
9 value::{SassFunction, Value},
10};
11use std::{
12 cell::RefCell,
13 collections::{BTreeMap, HashSet},
14 sync::Arc,
15};
16
17type Mutable<T> = Arc<RefCell<T>>;
18
19use super::{scope::Scopes, visitor::CallableContentBlock};
20
21#[derive(Debug, Clone)]
22pub(crate) struct Environment {
23 pub scopes: Scopes,
24 pub modules: Mutable<Modules>,
25 pub global_modules: Vec<Mutable<Module>>,
26 pub content: Option<Arc<CallableContentBlock>>,
27 pub forwarded_modules: Mutable<Vec<Mutable<Module>>>,
28 pub imported_modules: Mutable<Vec<Mutable<Module>>>,
29 #[allow(clippy::type_complexity)]
30 pub nested_forwarded_modules: Option<Mutable<Vec<Mutable<Vec<Mutable<Module>>>>>>,
31}
32
33impl Environment {
34 pub fn new() -> Self {
35 Self {
36 scopes: Scopes::new(),
37 modules: Arc::new(RefCell::new(Modules::new())),
38 global_modules: Vec::new(),
39 content: None,
40 forwarded_modules: Arc::new(RefCell::new(Vec::new())),
41 imported_modules: Arc::new(RefCell::new(Vec::new())),
42 nested_forwarded_modules: None,
43 }
44 }
45
46 pub fn new_closure(&self) -> Self {
47 Self {
48 scopes: self.scopes.new_closure(),
49 modules: Arc::clone(&self.modules),
50 global_modules: self.global_modules.iter().map(Arc::clone).collect(),
51 content: self.content.as_ref().map(Arc::clone),
52 forwarded_modules: Arc::clone(&self.forwarded_modules),
53 imported_modules: Arc::clone(&self.imported_modules),
54 nested_forwarded_modules: self.nested_forwarded_modules.as_ref().map(Arc::clone),
55 }
56 }
57
58 pub fn for_import(&self) -> Self {
59 Self {
60 scopes: self.scopes.new_closure(),
61 modules: Arc::new(RefCell::new(Modules::new())),
62 global_modules: Vec::new(),
63 content: self.content.as_ref().map(Arc::clone),
64 forwarded_modules: Arc::clone(&self.forwarded_modules),
65 imported_modules: Arc::clone(&self.imported_modules),
66 nested_forwarded_modules: self.nested_forwarded_modules.as_ref().map(Arc::clone),
67 }
68 }
69
70 pub fn to_dummy_module(&self, span: Span) -> Module {
71 Module::Environment {
72 scope: ModuleScope::new(),
73 upstream: Vec::new(),
74 extension_store: ExtensionStore::new(span),
75 env: self.clone(),
76 }
77 }
78
79 pub fn import_forwards(&mut self, _env: Module) {
84 if let Module::Environment { env, .. } = _env {
85 let mut forwarded = env.forwarded_modules;
86
87 if (*forwarded).borrow().is_empty() {
88 return;
89 }
90
91 let forwarded_modules = Arc::clone(&self.forwarded_modules);
94 if !(*forwarded_modules).borrow().is_empty() {
95 let mut x = Vec::new();
97 for entry in (*forwarded).borrow().iter() {
98 if !forwarded_modules
99 .borrow()
100 .iter()
101 .any(|module| Arc::ptr_eq(module, entry))
102 || !self
103 .global_modules
104 .iter()
105 .any(|module| Arc::ptr_eq(module, entry))
106 {
107 x.push(Arc::clone(entry));
108 }
109 }
110
111 forwarded = Arc::new(RefCell::new(x));
112 }
113
114 let forwarded_var_names = forwarded
115 .borrow()
116 .iter()
117 .flat_map(|module| (*module).borrow().scope().variables.keys())
118 .collect::<HashSet<Identifier>>();
119 let forwarded_fn_names = forwarded
120 .borrow()
121 .iter()
122 .flat_map(|module| (*module).borrow().scope().functions.keys())
123 .collect::<HashSet<Identifier>>();
124 let forwarded_mixin_names = forwarded
125 .borrow()
126 .iter()
127 .flat_map(|module| (*module).borrow().scope().mixins.keys())
128 .collect::<HashSet<Identifier>>();
129
130 if self.at_root() {
131 let mut to_remove = Vec::new();
132
133 for (idx, module) in (*self.imported_modules).borrow().iter().enumerate() {
136 let shadowed = ShadowedModule::if_necessary(
137 Arc::clone(module),
138 Some(&forwarded_var_names),
139 Some(&forwarded_fn_names),
140 Some(&forwarded_mixin_names),
141 );
142
143 if shadowed.is_some() {
144 to_remove.push(idx);
145 }
146 }
147
148 let mut imported_modules = (*self.imported_modules).borrow_mut();
149
150 for &idx in to_remove.iter().rev() {
151 imported_modules.remove(idx);
152 }
153
154 to_remove.clear();
155
156 for (idx, module) in (*self.forwarded_modules).borrow().iter().enumerate() {
157 let shadowed = ShadowedModule::if_necessary(
158 Arc::clone(module),
159 Some(&forwarded_var_names),
160 Some(&forwarded_fn_names),
161 Some(&forwarded_mixin_names),
162 );
163
164 if shadowed.is_some() {
165 to_remove.push(idx);
166 }
167 }
168
169 let mut forwarded_modules = (*self.forwarded_modules).borrow_mut();
170
171 for &idx in to_remove.iter().rev() {
172 forwarded_modules.remove(idx);
173 }
174
175 imported_modules.extend(forwarded.borrow().iter().map(Arc::clone));
176 forwarded_modules.extend(forwarded.borrow().iter().map(Arc::clone));
177 } else {
178 self.nested_forwarded_modules
179 .get_or_insert_with(|| {
180 Arc::new(RefCell::new(
181 (0..self.scopes.len())
182 .map(|_| Arc::new(RefCell::new(Vec::new())))
183 .collect(),
184 ))
185 })
186 .borrow_mut()
187 .last_mut()
188 .unwrap()
189 .borrow_mut()
190 .extend(forwarded.borrow().iter().map(Arc::clone));
191 }
192
193 for variable in forwarded_var_names {
196 (*self.scopes.variables)
197 .borrow_mut()
198 .last_mut()
199 .unwrap()
200 .borrow_mut()
201 .remove(&variable);
202 }
203 self.scopes.last_variable_index = None;
204
205 for func in forwarded_fn_names {
206 (*self.scopes.functions)
207 .borrow_mut()
208 .last_mut()
209 .unwrap()
210 .borrow_mut()
211 .remove(&func);
212 }
213 for mixin in forwarded_mixin_names {
214 (*self.scopes.mixins)
215 .borrow_mut()
216 .last_mut()
217 .unwrap()
218 .borrow_mut()
219 .remove(&mixin);
220 }
221 }
222 }
223
224 pub fn to_implicit_configuration(&self) -> Configuration {
225 let mut configuration = BTreeMap::new();
226
227 let variables = (*self.scopes.variables).borrow();
228
229 for variables in variables.iter() {
230 let entries = (**variables).borrow();
231 for (key, value) in entries.iter() {
232 configuration.insert(*key, ConfiguredValue::implicit(value.clone()));
235 }
236 }
237
238 Configuration::implicit(configuration)
239 }
240
241 pub fn forward_module(&mut self, module: Arc<RefCell<Module>>, rule: AstForwardRule) {
242 let view = ForwardedModule::if_necessary(module, rule);
243 (*self.forwarded_modules).borrow_mut().push(view);
244
245 }
247
248 pub fn insert_mixin(&mut self, name: Identifier, mixin: Mixin) {
249 self.scopes.insert_mixin(name, mixin);
250 }
251
252 pub fn mixin_exists(&self, name: Identifier) -> bool {
253 self.scopes.mixin_exists(name)
254 }
255
256 pub fn get_mixin(
257 &self,
258 name: Spanned<Identifier>,
259 namespace: Option<Spanned<Identifier>>,
260 ) -> SassResult<Mixin> {
261 if let Some(namespace) = namespace {
262 let modules = (*self.modules).borrow();
263 let module = modules.get(namespace.node, namespace.span)?;
264 return (*module).borrow().get_mixin(name);
265 }
266
267 match self.scopes.get_mixin(name) {
268 Ok(v) => Ok(v),
269 Err(e) => {
270 if let Some(v) = self.get_mixin_from_global_modules(name.node) {
271 return Ok(v);
272 }
273
274 Err(e)
275 }
276 }
277 }
278
279 pub fn insert_fn(&mut self, func: SassFunction) {
280 self.scopes.insert_fn(func);
281 }
282
283 pub fn fn_exists(&self, name: Identifier) -> bool {
284 self.scopes.fn_exists(name)
285 }
286
287 pub fn get_fn(
288 &self,
289 name: Identifier,
290 namespace: Option<Spanned<Identifier>>,
291 ) -> SassResult<Option<SassFunction>> {
292 if let Some(namespace) = namespace {
293 let modules = (*self.modules).borrow();
294 let module = modules.get(namespace.node, namespace.span)?;
295 return Ok((*module).borrow().get_fn(name));
296 }
297
298 Ok(self
299 .scopes
300 .get_fn(name)
301 .or_else(|| self.get_function_from_global_modules(name)))
302 }
303
304 pub fn var_exists(
305 &self,
306 name: Identifier,
307 namespace: Option<Spanned<Identifier>>,
308 ) -> SassResult<bool> {
309 if let Some(namespace) = namespace {
310 let modules = (*self.modules).borrow();
311 let module = modules.get(namespace.node, namespace.span)?;
312 return Ok((*module).borrow().var_exists(name));
313 }
314
315 Ok(self.scopes.var_exists(name))
316 }
317
318 pub fn get_var(
319 &mut self,
320 name: Spanned<Identifier>,
321 namespace: Option<Spanned<Identifier>>,
322 ) -> SassResult<Value> {
323 if let Some(namespace) = namespace {
324 let modules = (*self.modules).borrow();
325 let module = modules.get(namespace.node, namespace.span)?;
326 return (*module).borrow().get_var(name);
327 }
328
329 match self.scopes.get_var(name) {
330 Ok(v) => Ok(v),
331 Err(e) => {
332 if let Some(v) = self.get_variable_from_global_modules(name.node) {
333 Ok(v)
334 } else {
335 Err(e)
336 }
337 }
338 }
339 }
340
341 pub fn insert_var(
342 &mut self,
343 name: Spanned<Identifier>,
344 namespace: Option<Spanned<Identifier>>,
345 value: Value,
346 is_global: bool,
347 in_semi_global_scope: bool,
348 ) -> SassResult<()> {
349 if let Some(namespace) = namespace {
350 let mut modules = (*self.modules).borrow_mut();
351 let module = modules.get_mut(namespace.node, namespace.span)?;
352 (*module).borrow_mut().update_var(name, value)?;
353 return Ok(());
354 }
355
356 if is_global || self.at_root() {
357 if !self.scopes.global_var_exists(name.node) {
360 let module_with_name = self.from_one_module(name.node, "variable", |module| {
361 if module.borrow().var_exists(*name) {
362 Some(Arc::clone(module))
363 } else {
364 None
365 }
366 });
367
368 if let Some(module_with_name) = module_with_name {
369 module_with_name.borrow_mut().update_var(name, value)?;
370 return Ok(());
371 }
372 }
373
374 self.scopes.insert_var(0, name.node, value);
375 return Ok(());
376 }
377
378 let mut index = self
379 .scopes
380 .find_var(name.node)
381 .unwrap_or(self.scopes.len() - 1);
382
383 if !in_semi_global_scope && index == 0 {
384 index = self.scopes.len() - 1;
385 }
386
387 self.scopes.last_variable_index = Some((name.node, index));
388
389 self.scopes.insert_var(index, name.node, value);
390
391 Ok(())
392 }
393
394 pub fn at_root(&self) -> bool {
395 self.scopes.len() == 1
396 }
397
398 pub fn scopes_mut(&mut self) -> &mut Scopes {
399 &mut self.scopes
400 }
401
402 pub fn global_vars(&self) -> Arc<RefCell<BTreeMap<Identifier, Value>>> {
403 self.scopes.global_variables()
404 }
405
406 pub fn global_mixins(&self) -> Arc<RefCell<BTreeMap<Identifier, Mixin>>> {
407 self.scopes.global_mixins()
408 }
409
410 pub fn global_functions(&self) -> Arc<RefCell<BTreeMap<Identifier, SassFunction>>> {
411 self.scopes.global_functions()
412 }
413
414 fn get_variable_from_global_modules(&self, name: Identifier) -> Option<Value> {
415 self.from_one_module(name, "variable", |module| {
416 (**module).borrow().get_var_no_err(name)
417 })
418 }
419
420 fn get_function_from_global_modules(&self, name: Identifier) -> Option<SassFunction> {
421 self.from_one_module(name, "function", |module| (**module).borrow().get_fn(name))
422 }
423
424 fn get_mixin_from_global_modules(&self, name: Identifier) -> Option<Mixin> {
425 self.from_one_module(name, "mixin", |module| {
426 (**module).borrow().get_mixin_no_err(name)
427 })
428 }
429
430 pub fn add_module(
431 &mut self,
432 namespace: Option<Identifier>,
433 module: Arc<RefCell<Module>>,
434 span: Span,
435 ) -> SassResult<()> {
436 match namespace {
437 Some(namespace) => {
438 (*self.modules)
439 .borrow_mut()
440 .insert(namespace, module, span)?;
441 }
442 None => {
443 for name in (*self.scopes.global_variables()).borrow().keys() {
444 if (*module).borrow().var_exists(*name) {
445 return Err((
446 format!("This module and the new module both define a variable named \"${name}\".", name = name)
447 , span).into());
448 }
449 }
450
451 self.global_modules.push(module);
452 }
453 }
454
455 Ok(())
456 }
457
458 pub fn to_module(self, extension_store: ExtensionStore) -> Arc<RefCell<Module>> {
459 debug_assert!(self.at_root());
460
461 Arc::new(RefCell::new(Module::new_env(self, extension_store)))
462 }
463
464 fn from_one_module<T>(
465 &self,
466 _name: Identifier,
467 _ty: &str,
468 callback: impl Fn(&Arc<RefCell<Module>>) -> Option<T>,
469 ) -> Option<T> {
470 if let Some(nested_forwarded_modules) = &self.nested_forwarded_modules {
471 for modules in nested_forwarded_modules.borrow().iter().rev() {
472 for module in modules.borrow().iter().rev() {
473 if let Some(value) = callback(module) {
474 return Some(value);
475 }
476 }
477 }
478 }
479
480 for module in self.imported_modules.borrow().iter() {
481 if let Some(value) = callback(module) {
482 return Some(value);
483 }
484 }
485
486 let mut value: Option<T> = None;
487 for module in self.global_modules.iter() {
490 let value_in_module = match callback(module) {
491 Some(v) => v,
492 None => continue,
493 };
494
495 value = Some(value_in_module);
496
497 }
517
518 value
519 }
520}