2020-03-17 20:13:53 -04:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2020-04-12 19:37:12 -04:00
|
|
|
use codemap::Spanned;
|
|
|
|
|
2020-06-16 20:00:11 -04:00
|
|
|
use crate::{
|
|
|
|
atrule::{Function, Mixin},
|
|
|
|
builtin::GLOBAL_FUNCTIONS,
|
|
|
|
common::Identifier,
|
|
|
|
error::SassResult,
|
|
|
|
value::Value,
|
|
|
|
};
|
2020-03-17 20:13:53 -04:00
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
#[derive(Debug, Clone, Default)]
|
2020-03-17 20:13:53 -04:00
|
|
|
pub(crate) struct Scope {
|
2020-05-22 18:21:18 -04:00
|
|
|
vars: HashMap<Identifier, Spanned<Value>>,
|
|
|
|
mixins: HashMap<Identifier, Mixin>,
|
|
|
|
functions: HashMap<Identifier, Function>,
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
// todo: separate struct for global scope?
|
2020-03-17 20:13:53 -04:00
|
|
|
impl Scope {
|
|
|
|
#[must_use]
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
vars: HashMap::new(),
|
|
|
|
mixins: HashMap::new(),
|
|
|
|
functions: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
fn get_var_no_global(&self, name: &Spanned<Identifier>) -> SassResult<Spanned<Value>> {
|
|
|
|
match self.vars.get(&name.node) {
|
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => Err(("Undefined variable.", name.span).into()),
|
|
|
|
}
|
2020-04-04 14:53:08 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
pub fn get_var<T: Into<Identifier>>(
|
|
|
|
&self,
|
|
|
|
name: Spanned<T>,
|
|
|
|
global_scope: &Scope,
|
|
|
|
) -> SassResult<Spanned<Value>> {
|
2020-05-24 17:41:24 -04:00
|
|
|
let name = name.map_node(Into::into);
|
2020-04-12 19:37:12 -04:00
|
|
|
match self.vars.get(&name.node) {
|
2020-03-24 00:31:56 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-06-16 19:38:30 -04:00
|
|
|
None => global_scope.get_var_no_global(&name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 18:21:18 -04:00
|
|
|
pub fn insert_var<T: Into<Identifier>>(
|
|
|
|
&mut self,
|
|
|
|
s: T,
|
|
|
|
v: Spanned<Value>,
|
2020-07-03 12:38:20 -04:00
|
|
|
) -> Option<Spanned<Value>> {
|
|
|
|
self.vars.insert(s.into(), v)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
pub fn var_exists_no_global(&self, name: &Identifier) -> bool {
|
|
|
|
self.vars.contains_key(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn var_exists<'a, T: Into<&'a Identifier>>(&self, v: T, global_scope: &Scope) -> bool {
|
2020-05-22 18:21:18 -04:00
|
|
|
let name = v.into();
|
2020-06-16 19:38:30 -04:00
|
|
|
self.vars.contains_key(name) || global_scope.var_exists_no_global(name)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
fn get_mixin_no_global(&self, name: &Spanned<Identifier>) -> SassResult<Mixin> {
|
|
|
|
match self.mixins.get(&name.node) {
|
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => Err(("Undefined mixin.", name.span).into()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_mixin<T: Into<Identifier>>(
|
|
|
|
&self,
|
|
|
|
name: Spanned<T>,
|
|
|
|
global_scope: &Scope,
|
|
|
|
) -> SassResult<Mixin> {
|
2020-05-24 17:41:24 -04:00
|
|
|
let name = name.map_node(Into::into);
|
2020-04-12 19:37:12 -04:00
|
|
|
match self.mixins.get(&name.node) {
|
2020-04-04 14:53:08 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-06-16 19:38:30 -04:00
|
|
|
None => global_scope.get_mixin_no_global(&name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 18:21:18 -04:00
|
|
|
pub fn insert_mixin<T: Into<Identifier>>(&mut self, s: T, v: Mixin) -> Option<Mixin> {
|
|
|
|
self.mixins.insert(s.into(), v)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
fn mixin_exists_no_global(&self, name: &Identifier) -> bool {
|
|
|
|
self.mixins.contains_key(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn mixin_exists<T: Into<Identifier>>(&self, v: T, global_scope: &Scope) -> bool {
|
2020-05-22 18:21:18 -04:00
|
|
|
let name = v.into();
|
2020-06-16 19:38:30 -04:00
|
|
|
self.mixins.contains_key(&name) || global_scope.mixin_exists_no_global(&name)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_fn_no_global(&self, name: &Spanned<Identifier>) -> SassResult<Function> {
|
|
|
|
match self.functions.get(&name.node) {
|
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => Err(("Undefined function.", name.span).into()),
|
|
|
|
}
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
pub fn get_fn<T: Into<Identifier>>(
|
|
|
|
&self,
|
|
|
|
name: Spanned<T>,
|
|
|
|
global_scope: &Scope,
|
|
|
|
) -> SassResult<Function> {
|
2020-05-24 17:41:24 -04:00
|
|
|
let name = name.map_node(Into::into);
|
2020-04-12 19:37:12 -04:00
|
|
|
match self.functions.get(&name.node) {
|
2020-03-23 14:46:15 -04:00
|
|
|
Some(v) => Ok(v.clone()),
|
2020-06-16 19:38:30 -04:00
|
|
|
None => global_scope.get_fn_no_global(&name),
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 18:21:18 -04:00
|
|
|
pub fn insert_fn<T: Into<Identifier>>(&mut self, s: T, v: Function) -> Option<Function> {
|
|
|
|
self.functions.insert(s.into(), v)
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
|
2020-06-16 19:38:30 -04:00
|
|
|
fn fn_exists_no_global(&self, name: &Identifier) -> bool {
|
|
|
|
self.functions.contains_key(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fn_exists<T: Into<Identifier>>(&self, v: T, global_scope: &Scope) -> bool {
|
2020-05-22 18:21:18 -04:00
|
|
|
let name = v.into();
|
2020-06-16 19:38:30 -04:00
|
|
|
self.functions.contains_key(&name)
|
|
|
|
|| global_scope.fn_exists_no_global(&name)
|
|
|
|
|| GLOBAL_FUNCTIONS.contains_key(name.clone().into_inner().as_str())
|
2020-03-17 20:13:53 -04:00
|
|
|
}
|
|
|
|
}
|