grass/src/scope.rs

150 lines
4.6 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
2020-04-12 19:37:12 -04:00
use codemap::Spanned;
use crate::atrule::{Function, Mixin};
2020-06-16 19:38:30 -04:00
use crate::builtin::GLOBAL_FUNCTIONS;
use crate::common::Identifier;
2020-03-22 15:08:13 -04:00
use crate::error::SassResult;
use crate::value::Value;
2020-06-16 19:38:30 -04:00
#[derive(Debug, Clone, Default)]
pub(crate) struct Scope {
vars: HashMap<Identifier, Spanned<Value>>,
mixins: HashMap<Identifier, Mixin>,
functions: HashMap<Identifier, Function>,
}
2020-06-16 19:38:30 -04:00
// todo: separate struct for global scope?
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) {
Some(v) => Ok(v.clone()),
2020-06-16 19:38:30 -04:00
None => global_scope.get_var_no_global(&name),
}
}
pub fn insert_var<T: Into<Identifier>>(
&mut self,
s: T,
v: Spanned<Value>,
) -> SassResult<Option<Spanned<Value>>> {
2020-04-12 19:37:12 -04:00
let Spanned { node, span } = v;
Ok(self.vars.insert(s.into(), node.eval(span)?))
}
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 {
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-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),
}
}
pub fn insert_mixin<T: Into<Identifier>>(&mut self, s: T, v: Mixin) -> Option<Mixin> {
self.mixins.insert(s.into(), v)
}
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 {
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-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) {
Some(v) => Ok(v.clone()),
2020-06-16 19:38:30 -04:00
None => global_scope.get_fn_no_global(&name),
}
}
pub fn insert_fn<T: Into<Identifier>>(&mut self, s: T, v: Function) -> Option<Function> {
self.functions.insert(s.into(), v)
}
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 {
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())
// special functions not in the `GLOBAL_FUNCTIONS` map
|| matches!(
name.into_inner().as_str(),
"function-exists"
| "content-exists"
| "mixin-exists"
| "variable-exists"
| "global-variable-exists"
| "get-function"
| "call"
)
}
2020-06-16 19:38:30 -04:00
#[allow(dead_code)]
pub fn extend(&mut self, other: Scope) {
self.vars.extend(other.vars);
self.mixins.extend(other.mixins);
self.functions.extend(other.functions);
}
}