2020-03-17 20:13:53 -04:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
use codemap::Spanned;
|
|
|
|
|
2020-03-22 14:26:33 -04:00
|
|
|
use crate::atrule::{Function, Mixin};
|
2020-03-22 15:08:13 -04:00
|
|
|
use crate::error::SassResult;
|
2020-03-17 20:13:53 -04:00
|
|
|
use crate::value::Value;
|
|
|
|
|
|
|
|
thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell<Scope> = RefCell::new(Scope::new()));
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub(crate) fn get_global_var(s: Spanned<String>) -> SassResult<Spanned<Value>> {
|
|
|
|
GLOBAL_SCOPE.with(|scope| match scope.borrow().vars().get(&s.node) {
|
2020-03-17 20:13:53 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-04-12 19:37:12 -04:00
|
|
|
None => Err(("Undefined variable.", s.span).into()),
|
2020-03-17 20:13:53 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-04 14:53:08 -04:00
|
|
|
pub(crate) fn global_var_exists(v: &str) -> bool {
|
2020-04-23 18:14:42 -04:00
|
|
|
GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(&v.replace('_', "-")))
|
2020-04-04 14:53:08 -04:00
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub(crate) fn insert_global_var(s: &str, v: Spanned<Value>) -> SassResult<Option<Spanned<Value>>> {
|
2020-04-04 14:53:08 -04:00
|
|
|
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v))
|
2020-03-23 14:53:22 -04:00
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub(crate) fn get_global_fn(s: Spanned<String>) -> SassResult<Function> {
|
|
|
|
GLOBAL_SCOPE.with(|scope| match scope.borrow().functions().get(&s.node) {
|
2020-03-23 14:46:15 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-04-12 19:37:12 -04:00
|
|
|
None => Err(("Undefined function.", s.span).into()),
|
2020-03-23 14:46:15 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-04 14:53:08 -04:00
|
|
|
pub(crate) fn global_fn_exists(v: &str) -> bool {
|
2020-04-23 18:14:42 -04:00
|
|
|
GLOBAL_SCOPE.with(|scope| {
|
|
|
|
scope
|
|
|
|
.borrow()
|
|
|
|
.functions()
|
|
|
|
.contains_key(&v.replace('_', "-"))
|
|
|
|
})
|
2020-04-04 14:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn insert_global_fn(s: &str, v: Function) -> Option<Function> {
|
|
|
|
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s, v))
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub(crate) fn get_global_mixin(s: Spanned<String>) -> SassResult<Mixin> {
|
|
|
|
GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(&s.node) {
|
2020-04-04 14:53:08 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-04-12 19:37:12 -04:00
|
|
|
None => Err(("Undefined mixin.", s.span).into()),
|
2020-04-04 14:53:08 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn global_mixin_exists(v: &str) -> bool {
|
2020-04-23 18:14:42 -04:00
|
|
|
GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(&v.replace('_', "-")))
|
2020-04-04 14:53:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn insert_global_mixin(s: &str, v: Mixin) -> Option<Mixin> {
|
|
|
|
GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s, v))
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct Scope {
|
2020-04-12 19:37:12 -04:00
|
|
|
vars: HashMap<String, Spanned<Value>>,
|
2020-03-17 20:13:53 -04:00
|
|
|
mixins: HashMap<String, Mixin>,
|
|
|
|
functions: HashMap<String, Function>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Scope {
|
|
|
|
#[must_use]
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
vars: HashMap::new(),
|
|
|
|
mixins: HashMap::new(),
|
|
|
|
functions: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub const fn vars(&self) -> &HashMap<String, Spanned<Value>> {
|
2020-03-17 20:13:53 -04:00
|
|
|
&self.vars
|
|
|
|
}
|
|
|
|
|
2020-03-23 14:46:15 -04:00
|
|
|
pub const fn functions(&self) -> &HashMap<String, Function> {
|
|
|
|
&self.functions
|
|
|
|
}
|
|
|
|
|
2020-04-04 14:53:08 -04:00
|
|
|
pub const fn mixins(&self) -> &HashMap<String, Mixin> {
|
|
|
|
&self.mixins
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn get_var(&self, mut name: Spanned<String>) -> SassResult<Spanned<Value>> {
|
|
|
|
name.node = name.node.replace('_', "-");
|
|
|
|
match self.vars.get(&name.node) {
|
2020-03-24 00:31:56 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => get_global_var(name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn insert_var(&mut self, s: &str, v: Spanned<Value>) -> SassResult<Option<Spanned<Value>>> {
|
|
|
|
let Spanned { node, span } = v;
|
|
|
|
Ok(self.vars.insert(s.replace('_', "-"), node.eval(span)?))
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn var_exists(&self, v: &str) -> bool {
|
2020-04-04 14:53:08 -04:00
|
|
|
let name = &v.replace('_', "-");
|
|
|
|
self.vars.contains_key(name) || global_var_exists(name)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn get_mixin(&self, mut name: Spanned<String>) -> SassResult<Mixin> {
|
|
|
|
name.node = name.node.replace('_', "-");
|
|
|
|
match self.mixins.get(&name.node) {
|
2020-04-04 14:53:08 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => get_global_mixin(name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_mixin(&mut self, s: &str, v: Mixin) -> Option<Mixin> {
|
|
|
|
self.mixins.insert(s.replace('_', "-"), v)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn mixin_exists(&self, v: &str) -> bool {
|
2020-04-04 14:53:08 -04:00
|
|
|
let name = &v.replace('_', "-");
|
|
|
|
self.mixins.contains_key(name) || global_mixin_exists(name)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
pub fn get_fn(&self, mut name: Spanned<String>) -> SassResult<Function> {
|
|
|
|
name.node = name.node.replace('_', "-");
|
|
|
|
match self.functions.get(&name.node) {
|
2020-03-23 14:46:15 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => get_global_fn(name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_fn(&mut self, s: &str, v: Function) -> Option<Function> {
|
|
|
|
self.functions.insert(s.replace('_', "-"), v)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fn_exists(&self, v: &str) -> bool {
|
2020-04-04 14:53:08 -04:00
|
|
|
let name = &v.replace('_', "-");
|
|
|
|
self.functions.contains_key(name) || global_fn_exists(name)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extend(&mut self, other: Scope) {
|
|
|
|
self.vars.extend(other.vars);
|
|
|
|
self.mixins.extend(other.mixins);
|
|
|
|
self.functions.extend(other.functions);
|
|
|
|
}
|
|
|
|
}
|