From ece0f5afde9bfd9207b5e5cbc9ed00352096aa4e Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sat, 4 Apr 2020 14:53:08 -0400 Subject: [PATCH] allow !global in mixins and functions --- src/lib.rs | 18 +++++++---------- src/scope.rs | 53 +++++++++++++++++++++++++++++++++++++++----------- tests/scope.rs | 5 +++++ 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3efc058..5d9b00f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,7 +91,7 @@ pub use crate::error::{SassError, SassResult}; use crate::format::PrettyPrinter; use crate::imports::import; use crate::lexer::Lexer; -use crate::scope::{insert_global_var, Scope, GLOBAL_SCOPE}; +use crate::scope::{insert_global_fn, insert_global_mixin, insert_global_var, Scope, GLOBAL_SCOPE}; use crate::selector::Selector; use crate::style::Style; pub(crate) use crate::token::Token; @@ -284,7 +284,7 @@ impl<'a> StyleSheetParser<'a> { match kind { 'a'..='z' | 'A'..='Z' | '_' | '-' | '[' | '#' | ':' | '*' | '%' | '.' | '>' => rules - .extend(self.eat_rules(&Selector::new(), &mut GLOBAL_SCOPE.with(|s| s.borrow().clone()))?), + .extend(self.eat_rules(&Selector::new(), &mut Scope::new())?), &'\t' | &'\n' | ' ' => { self.lexer.next(); continue; @@ -303,7 +303,7 @@ impl<'a> StyleSheetParser<'a> { return Err("expected \":\".".into()); } let VariableDecl { val, default, .. } = - eat_variable_value(&mut self.lexer, &GLOBAL_SCOPE.with(|s| s.borrow().clone()), &Selector::new())?; + eat_variable_value(&mut self.lexer, &Scope::new(), &Selector::new())?; GLOBAL_SCOPE.with(|s| { if !default || s.borrow().get_var(&name).is_err() { match s.borrow_mut().insert_var(&name, val) { @@ -336,7 +336,7 @@ impl<'a> StyleSheetParser<'a> { match AtRuleKind::from(at_rule_kind.as_str()) { AtRuleKind::Include => rules.extend(eat_include( &mut self.lexer, - &GLOBAL_SCOPE.with(|s| s.borrow().clone()), + &Scope::new(), &Selector::new(), )?), AtRuleKind::Import => { @@ -364,16 +364,12 @@ impl<'a> StyleSheetParser<'a> { }); } v => { - match AtRule::from_tokens(&v, Pos::new(), &mut self.lexer, &mut GLOBAL_SCOPE.with(|s| s.borrow().clone()), &Selector::new())? { + match AtRule::from_tokens(&v, Pos::new(), &mut self.lexer, &mut Scope::new(), &Selector::new())? { AtRule::Mixin(name, mixin) => { - GLOBAL_SCOPE.with(|s| { - s.borrow_mut().insert_mixin(&name, *mixin); - }); + insert_global_mixin(&name, *mixin); } AtRule::Function(name, func) => { - GLOBAL_SCOPE.with(|s| { - s.borrow_mut().insert_fn(&name, *func); - }); + insert_global_fn(&name, *func); } AtRule::Charset => continue, AtRule::Error(pos, message) => self.error(pos, &message), diff --git a/src/scope.rs b/src/scope.rs index 068b52a..a3f2de2 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -14,8 +14,12 @@ pub(crate) fn get_global_var(s: &str) -> SassResult { }) } -pub fn global_var_exists(v: &str) -> bool { - GLOBAL_SCOPE.with(|scope| scope.borrow().var_exists(v)) +pub(crate) fn global_var_exists(v: &str) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(v)) +} + +pub(crate) fn insert_global_var(s: &str, v: Value) -> SassResult> { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v)) } pub(crate) fn get_global_fn(s: &str) -> SassResult { @@ -25,8 +29,27 @@ pub(crate) fn get_global_fn(s: &str) -> SassResult { }) } -pub(crate) fn insert_global_var(s: &str, v: Value) -> SassResult> { - GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v)) +pub(crate) fn global_fn_exists(v: &str) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().functions().contains_key(v)) +} + +pub(crate) fn insert_global_fn(s: &str, v: Function) -> Option { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s, v)) +} + +pub(crate) fn get_global_mixin(s: &str) -> SassResult { + GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(s) { + Some(v) => Ok(v.clone()), + None => Err("Undefined mixin.".into()), + }) +} + +pub(crate) fn global_mixin_exists(v: &str) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(v)) +} + +pub(crate) fn insert_global_mixin(s: &str, v: Mixin) -> Option { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s, v)) } #[derive(Debug, Clone)] @@ -54,6 +77,10 @@ impl Scope { &self.functions } + pub const fn mixins(&self) -> &HashMap { + &self.mixins + } + pub fn get_var(&self, v: &str) -> SassResult { let name = &v.replace('_', "-"); match self.vars.get(name) { @@ -67,13 +94,15 @@ impl Scope { } pub fn var_exists(&self, v: &str) -> bool { - self.vars.contains_key(&v.replace('_', "-")) + let name = &v.replace('_', "-"); + self.vars.contains_key(name) || global_var_exists(name) } - pub fn get_mixin(&self, v: &str) -> SassResult<&Mixin> { - match self.mixins.get(&v.replace('_', "-")) { - Some(v) => Ok(v), - None => Err("Undefined mixin.".into()), + pub fn get_mixin(&self, v: &str) -> SassResult { + let name = &v.replace('_', "-"); + match self.mixins.get(name) { + Some(v) => Ok(v.clone()), + None => get_global_mixin(name), } } @@ -82,7 +111,8 @@ impl Scope { } pub fn mixin_exists(&self, v: &str) -> bool { - self.mixins.contains_key(&v.replace('_', "-")) + let name = &v.replace('_', "-"); + self.mixins.contains_key(name) || global_mixin_exists(name) } pub fn get_fn(&self, v: &str) -> SassResult { @@ -98,7 +128,8 @@ impl Scope { } pub fn fn_exists(&self, v: &str) -> bool { - self.functions.contains_key(&v.replace('_', "-")) + let name = &v.replace('_', "-"); + self.functions.contains_key(name) || global_fn_exists(name) } pub fn extend(&mut self, other: Scope) { diff --git a/tests/scope.rs b/tests/scope.rs index 98d14a9..24327f5 100644 --- a/tests/scope.rs +++ b/tests/scope.rs @@ -18,3 +18,8 @@ test!( "$foo: 42;\n\n.foo {\n content: $foo;\n $foo: 1337 !global;\n content: $foo;\n}\n\n.bar {\n content: $foo;\n}\n", ".foo {\n content: 42;\n content: 1337;\n}\n\n.bar {\n content: 1337;\n}\n" ); +test!( + global_in_mixin, + "$y: a;\n@mixin foo {\n $y: b !global;\n}\na {\n @include foo;\n color: $y;\n}\n", + "a {\n color: b;\n}\n" +);