From 2102781f628fe234bcaf9bb3fe3e0c9e39c10c50 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Fri, 22 May 2020 18:21:18 -0400 Subject: [PATCH] create structure for identifiers it looks like rustfmt also updated during this commit, so there are some formatting changes --- src/atrule/each_rule.rs | 4 +- src/common.rs | 27 ++++++++++ src/scope.rs | 111 +++++++++++++++++++++------------------- src/stylesheet.rs | 93 ++++++++++++++++++++++----------- 4 files changed, 150 insertions(+), 85 deletions(-) diff --git a/src/atrule/each_rule.rs b/src/atrule/each_rule.rs index 6b4f3ef..676d908 100644 --- a/src/atrule/each_rule.rs +++ b/src/atrule/each_rule.rs @@ -42,7 +42,7 @@ impl Each { if self.vars.len() == 1 { if this_iterator.len() == 1 { scope.insert_var( - &self.vars[0], + &self.vars[0].node, Spanned { node: this_iterator[0].clone(), span: self.vars[0].span, @@ -50,7 +50,7 @@ impl Each { )?; } else { scope.insert_var( - &self.vars[0], + &self.vars[0].node, Spanned { node: Value::List(this_iterator, ListSeparator::Space, Brackets::None), span: self.vars[0].span, diff --git a/src/common.rs b/src/common.rs index d01d51a..163fece 100644 --- a/src/common.rs +++ b/src/common.rs @@ -119,3 +119,30 @@ impl Display for QualifiedName { f.write_str(&self.ident) } } + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub(crate) struct Identifier(String); + +impl From for Identifier { + fn from(s: String) -> Identifier { + Identifier(s.replace('_', "-")) + } +} + +impl From<&String> for Identifier { + fn from(s: &String) -> Identifier { + Identifier(s.replace('_', "-")) + } +} + +impl From<&str> for Identifier { + fn from(s: &str) -> Identifier { + Identifier(s.replace('_', "-")) + } +} + +impl Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/scope.rs b/src/scope.rs index 54a6751..f374a9f 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -4,66 +4,67 @@ use std::collections::HashMap; use codemap::Spanned; use crate::atrule::{Function, Mixin}; +use crate::common::Identifier; use crate::error::SassResult; use crate::value::Value; thread_local!(pub(crate) static GLOBAL_SCOPE: RefCell = RefCell::new(Scope::new())); -pub(crate) fn get_global_var(s: Spanned) -> SassResult> { - GLOBAL_SCOPE.with(|scope| match scope.borrow().vars().get(&s.node) { +pub(crate) fn get_global_var>(s: Spanned) -> SassResult> { + GLOBAL_SCOPE.with(|scope| match scope.borrow().vars().get(&s.node.into()) { Some(v) => Ok(v.clone()), None => Err(("Undefined variable.", s.span).into()), }) } -pub(crate) fn global_var_exists(v: &str) -> bool { - GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(&v.replace('_', "-"))) +pub(crate) fn global_var_exists>(v: T) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().vars().contains_key(&v.into())) } -pub(crate) fn insert_global_var(s: &str, v: Spanned) -> SassResult>> { - GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s, v)) +pub(crate) fn insert_global_var>( + s: T, + v: Spanned, +) -> SassResult>> { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_var(s.into(), v)) } -pub(crate) fn get_global_fn(s: Spanned) -> SassResult { - GLOBAL_SCOPE.with(|scope| match scope.borrow().functions().get(&s.node) { - Some(v) => Ok(v.clone()), - None => Err(("Undefined function.", s.span).into()), - }) +pub(crate) fn get_global_fn>(s: Spanned) -> SassResult { + GLOBAL_SCOPE.with( + |scope| match scope.borrow().functions().get(&s.node.into()) { + Some(v) => Ok(v.clone()), + None => Err(("Undefined function.", s.span).into()), + }, + ) } -pub(crate) fn global_fn_exists(v: &str) -> bool { - GLOBAL_SCOPE.with(|scope| { - scope - .borrow() - .functions() - .contains_key(&v.replace('_', "-")) - }) +pub(crate) fn global_fn_exists>(v: T) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().functions().contains_key(&v.into())) } -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 insert_global_fn>(s: T, v: Function) -> Option { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_fn(s.into(), v)) } -pub(crate) fn get_global_mixin(s: Spanned) -> SassResult { - GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(&s.node) { +pub(crate) fn get_global_mixin>(s: Spanned) -> SassResult { + GLOBAL_SCOPE.with(|scope| match scope.borrow().mixins().get(&s.node.into()) { Some(v) => Ok(v.clone()), None => Err(("Undefined mixin.", s.span).into()), }) } -pub(crate) fn global_mixin_exists(v: &str) -> bool { - GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(&v.replace('_', "-"))) +pub(crate) fn global_mixin_exists>(v: T) -> bool { + GLOBAL_SCOPE.with(|scope| scope.borrow().mixins().contains_key(&v.into())) } -pub(crate) fn insert_global_mixin(s: &str, v: Mixin) -> Option { - GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s, v)) +pub(crate) fn insert_global_mixin>(s: T, v: Mixin) -> Option { + GLOBAL_SCOPE.with(|scope| scope.borrow_mut().insert_mixin(s.into(), v)) } #[derive(Debug, Clone)] pub(crate) struct Scope { - vars: HashMap>, - mixins: HashMap, - functions: HashMap, + vars: HashMap>, + mixins: HashMap, + functions: HashMap, } impl Scope { @@ -76,68 +77,72 @@ impl Scope { } } - pub const fn vars(&self) -> &HashMap> { + pub const fn vars(&self) -> &HashMap> { &self.vars } - pub const fn functions(&self) -> &HashMap { + pub const fn functions(&self) -> &HashMap { &self.functions } - pub const fn mixins(&self) -> &HashMap { + pub const fn mixins(&self) -> &HashMap { &self.mixins } - pub fn get_var(&self, mut name: Spanned) -> SassResult> { - name.node = name.node.replace('_', "-"); + pub fn get_var>(&self, name: Spanned) -> SassResult> { + let name = name.map_node(|n| n.into()); match self.vars.get(&name.node) { Some(v) => Ok(v.clone()), None => get_global_var(name), } } - pub fn insert_var(&mut self, s: &str, v: Spanned) -> SassResult>> { + pub fn insert_var>( + &mut self, + s: T, + v: Spanned, + ) -> SassResult>> { let Spanned { node, span } = v; - Ok(self.vars.insert(s.replace('_', "-"), node.eval(span)?)) + Ok(self.vars.insert(s.into(), node.eval(span)?)) } - pub fn var_exists(&self, v: &str) -> bool { - let name = &v.replace('_', "-"); - self.vars.contains_key(name) || global_var_exists(name) + pub fn var_exists>(&self, v: T) -> bool { + let name = v.into(); + self.vars.contains_key(&name) || global_var_exists(name) } - pub fn get_mixin(&self, mut name: Spanned) -> SassResult { - name.node = name.node.replace('_', "-"); + pub fn get_mixin>(&self, name: Spanned) -> SassResult { + let name = name.map_node(|n| n.into()); match self.mixins.get(&name.node) { Some(v) => Ok(v.clone()), None => get_global_mixin(name), } } - pub fn insert_mixin(&mut self, s: &str, v: Mixin) -> Option { - self.mixins.insert(s.replace('_', "-"), v) + pub fn insert_mixin>(&mut self, s: T, v: Mixin) -> Option { + self.mixins.insert(s.into(), v) } - pub fn mixin_exists(&self, v: &str) -> bool { - let name = &v.replace('_', "-"); - self.mixins.contains_key(name) || global_mixin_exists(name) + pub fn mixin_exists>(&self, v: T) -> bool { + let name = v.into(); + self.mixins.contains_key(&name) || global_mixin_exists(name) } - pub fn get_fn(&self, mut name: Spanned) -> SassResult { - name.node = name.node.replace('_', "-"); + pub fn get_fn>(&self, name: Spanned) -> SassResult { + let name = name.map_node(|n| n.into()); match self.functions.get(&name.node) { Some(v) => Ok(v.clone()), None => get_global_fn(name), } } - pub fn insert_fn(&mut self, s: &str, v: Function) -> Option { - self.functions.insert(s.replace('_', "-"), v) + pub fn insert_fn>(&mut self, s: T, v: Function) -> Option { + self.functions.insert(s.into(), v) } - pub fn fn_exists(&self, v: &str) -> bool { - let name = &v.replace('_', "-"); - self.functions.contains_key(name) || global_fn_exists(name) + pub fn fn_exists>(&self, v: T) -> bool { + let name = v.into(); + self.functions.contains_key(&name) || global_fn_exists(name) } pub fn extend(&mut self, other: Scope) { diff --git a/src/stylesheet.rs b/src/stylesheet.rs index 3fb6e0b..78baa47 100644 --- a/src/stylesheet.rs +++ b/src/stylesheet.rs @@ -164,8 +164,9 @@ impl<'a> StyleSheetParser<'a> { let mut rules: Vec> = Vec::new(); while let Some(Token { kind, .. }) = self.lexer.peek() { match kind { - _ if is_selector_char(*kind) => rules - .extend(self.eat_rules(&Selector::new(), &mut Scope::new())?), + _ if is_selector_char(*kind) => { + rules.extend(self.eat_rules(&Selector::new(), &mut Scope::new())?) + } '\t' | '\n' | ' ' => { self.lexer.next(); continue; @@ -177,14 +178,15 @@ impl<'a> StyleSheetParser<'a> { match self.lexer.peek() { Some(Token { kind: ':', .. }) => { - self.lexer.take(name.node.chars().count() + whitespace + 1) + self.lexer + .take(name.node.chars().count() + whitespace + 1) .for_each(drop); devour_whitespace(self.lexer); let VariableDecl { val, default, .. } = - eat_variable_value(self.lexer, &Scope::new(), &Selector::new())?; + eat_variable_value(self.lexer, &Scope::new(), &Selector::new())?; - if !(default && global_var_exists(&name)) { + if !(default && global_var_exists(&name.node)) { insert_global_var(&name.node, val)?; } } @@ -202,17 +204,15 @@ impl<'a> StyleSheetParser<'a> { let comment = eat_comment(self.lexer, &Scope::new(), &Selector::new())?; rules.push(comment.map_node(Stmt::MultilineComment)); } - _ => return Err(("expected selector.", pos).into()) + _ => return Err(("expected selector.", pos).into()), } } '@' => { let span_before = self.lexer.next().unwrap().pos(); - let Spanned { node: at_rule_kind, span } = eat_ident( - self.lexer, - &Scope::new(), - &Selector::new(), - span_before - )?; + let Spanned { + node: at_rule_kind, + span, + } = eat_ident(self.lexer, &Scope::new(), &Selector::new(), span_before)?; if at_rule_kind.is_empty() { return Err(("Expected identifier.", span).into()); } @@ -222,14 +222,14 @@ impl<'a> StyleSheetParser<'a> { &Scope::new(), &Selector::new(), None, - span + span, )?), AtRuleKind::Import => { devour_whitespace(self.lexer); let mut file_name = String::new(); let next = match self.lexer.next() { Some(v) => v, - None => todo!("expected input after @import") + None => todo!("expected input after @import"), }; match next.kind { q @ '"' | q @ '\'' => { @@ -238,8 +238,12 @@ impl<'a> StyleSheetParser<'a> { self.lexer, &Scope::new(), q, - &Selector::new())? - .node.unquote().to_css_string(span)?); + &Selector::new(), + )? + .node + .unquote() + .to_css_string(span)?, + ); } _ => return Err(("Expected string.", next.pos()).into()), } @@ -251,14 +255,22 @@ impl<'a> StyleSheetParser<'a> { devour_whitespace(self.lexer); - let (new_rules, new_scope) = import(self.path, file_name.as_ref(), &mut self.map)?; + let (new_rules, new_scope) = + import(self.path, file_name.as_ref(), &mut self.map)?; rules.extend(new_rules); GLOBAL_SCOPE.with(|s| { s.borrow_mut().extend(new_scope); }); } v => { - let rule = AtRule::from_tokens(v, span, self.lexer, &mut Scope::new(), &Selector::new(), None)?; + let rule = AtRule::from_tokens( + v, + span, + self.lexer, + &mut Scope::new(), + &Selector::new(), + None, + )?; match rule.node { AtRule::Mixin(name, mixin) => { insert_global_mixin(&name, *mixin); @@ -274,17 +286,36 @@ impl<'a> StyleSheetParser<'a> { ("This at-rule is not allowed here.", rule.span).into() ) } - AtRule::For(f) => rules.extend(f.ruleset_eval(&mut Scope::new(), &Selector::new(), None)?), - AtRule::While(w) => rules.extend(w.ruleset_eval(&mut Scope::new(), &Selector::new(), true, None)?), - AtRule::Each(e) => { - rules.extend(e.ruleset_eval(&mut Scope::new(), &Selector::new(), None)?) - } + AtRule::For(f) => rules.extend(f.ruleset_eval( + &mut Scope::new(), + &Selector::new(), + None, + )?), + AtRule::While(w) => rules.extend(w.ruleset_eval( + &mut Scope::new(), + &Selector::new(), + true, + None, + )?), + AtRule::Each(e) => rules.extend(e.ruleset_eval( + &mut Scope::new(), + &Selector::new(), + None, + )?), AtRule::Include(s) => rules.extend(s), - AtRule::Content => return Err( - ("@content is only allowed within mixin declarations.", rule.span - ).into()), + AtRule::Content => { + return Err(( + "@content is only allowed within mixin declarations.", + rule.span, + ) + .into()) + } AtRule::If(i) => { - rules.extend(i.eval(&mut Scope::new(), &Selector::new(), None)?); + rules.extend(i.eval( + &mut Scope::new(), + &Selector::new(), + None, + )?); } AtRule::AtRoot(root_rules) => rules.extend(root_rules), AtRule::Unknown(..) => rules.push(rule.map_node(Stmt::AtRule)), @@ -292,11 +323,13 @@ impl<'a> StyleSheetParser<'a> { } } } - }, + } '&' => { - return Err( - ("Top-level selectors may not contain the parent selector \"&\".", self.lexer.next().unwrap().pos()).into(), + return Err(( + "Top-level selectors may not contain the parent selector \"&\".", + self.lexer.next().unwrap().pos(), ) + .into()) } c if c.is_control() => { return Err(("expected selector.", self.lexer.next().unwrap().pos()).into());