Treat - and _ as the same in identifiers

This commit is contained in:
ConnorSkees 2020-02-08 17:26:01 -05:00
parent 783e43b765
commit fa582b3316
8 changed files with 75 additions and 30 deletions

View File

@ -144,11 +144,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
toks.next();
match name {
Some(ref name) => {
args.insert(name.clone(), scope.vars.get(&v).unwrap().clone())
args.insert(name.clone(), scope.get_var(&v).unwrap().clone())
}
None => args.insert(
format!("{}", args.len()),
scope.vars.get(&v).unwrap().clone(),
scope.get_var(&v).unwrap().clone(),
),
};
if let Some(ref mut s) = name {
@ -162,10 +162,10 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
}) => {
toks.next();
match name {
Some(name) => args.insert(name, scope.vars.get(&v).unwrap().clone()),
Some(name) => args.insert(name, scope.get_var(&v).unwrap().clone()),
None => args.insert(
format!("{}", args.len()),
scope.vars.get(&v).unwrap().clone(),
scope.get_var(&v).unwrap().clone(),
),
};
break;

View File

@ -342,9 +342,9 @@ impl Display for Pos {
#[derive(Debug, Clone)]
pub(crate) struct Scope {
pub vars: HashMap<String, Value>,
pub mixins: HashMap<String, Mixin>,
pub functions: HashMap<String, Function>,
vars: HashMap<String, Value>,
mixins: HashMap<String, Mixin>,
functions: HashMap<String, Function>,
}
impl Scope {
@ -357,7 +357,52 @@ impl Scope {
}
}
pub fn merge(&mut self, other: Scope) {
pub fn get_var(&self, v: &str) -> Result<&Value, String> {
match self.vars.get(&v.replace('_', "-")) {
Some(v) => Ok(v),
None => Err(format!("Undefined variable `{}`.", v))
}
}
pub fn insert_var(&mut self, s: &str, v: Value) -> Option<Value> {
self.vars.insert(s.replace('_', "-"), v)
}
pub fn var_exists(&self, v: &str) -> bool {
self.vars.contains_key(&v.replace('_', "-"))
}
pub fn get_mixin(&self, v: &str) -> Result<&Mixin, String> {
match self.mixins.get(&v.replace('_', "-")) {
Some(v) => Ok(v),
None => Err(format!("Undefined mixin `{}`.", v))
}
}
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 {
self.mixins.contains_key(&v.replace('_', "-"))
}
pub fn get_fn(&self, v: &str) -> Result<&Function, String> {
match self.functions.get(&v.replace('_', "-")) {
Some(v) => Ok(v),
None => Err(format!("Undefined function `{}`.", v))
}
}
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 {
self.functions.contains_key(&v.replace('_', "-"))
}
pub fn extend(&mut self, other: Scope) {
self.vars.extend(other.vars);
self.mixins.extend(other.mixins);
self.functions.extend(other.functions);

View File

@ -75,7 +75,7 @@ impl Function {
None => arg.default.clone().expect("missing variable!"),
},
};
self.scope.vars.insert(arg.name.clone(), val);
self.scope.insert_var(&arg.name, val);
}
self
}

View File

@ -34,7 +34,7 @@ pub(crate) fn import<P: AsRef<Path>>(path: P) -> SassResult<(Vec<Stmt>, Scope)>
let (rules2, scope2) =
StyleSheet::export_from_path(name.to_str().expect("path should be UTF-8"))?;
rules.extend(rules2);
scope.merge(scope2);
scope.extend(scope2);
}
}
Ok((rules, scope))

View File

@ -353,8 +353,8 @@ impl<'a> StyleSheetParser<'a> {
}
let VariableDecl { val, default } = eat_variable_value(&mut self.lexer, &self.global_scope)
.unwrap_or_else(|err| self.error(err.0, &err.1));
if !default || self.global_scope.vars.get(&name).is_none() {
self.global_scope.vars.insert(name, val);
if !default || self.global_scope.get_var(&name).is_err() {
self.global_scope.insert_var(&name, val);
}
}
TokenKind::MultilineComment(_) => {
@ -413,7 +413,7 @@ impl<'a> StyleSheetParser<'a> {
let (new_rules, new_scope) = import(file_name)?;
rules.extend(new_rules);
self.global_scope.merge(new_scope);
self.global_scope.extend(new_scope);
}
TokenKind::AtRule(_) => {
if let Some(Token {
@ -423,10 +423,10 @@ impl<'a> StyleSheetParser<'a> {
{
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope) {
AtRule::Mixin(name, mixin) => {
self.global_scope.mixins.insert(name, *mixin);
self.global_scope.insert_mixin(&name, *mixin);
}
AtRule::Function(name, func) => {
self.global_scope.functions.insert(name, *func);
self.global_scope.insert_fn(&name, *func);
}
AtRule::Charset(toks) => rules.push(Stmt::AtRule(AtRule::Charset(toks))),
AtRule::Error(pos, message) => self.error(pos, &message),
@ -458,10 +458,10 @@ impl<'a> StyleSheetParser<'a> {
#[allow(clippy::redundant_closure)]
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
Expr::MixinDecl(name, mixin) => {
scope.mixins.insert(name, *mixin);
scope.insert_mixin(&name, *mixin);
}
Expr::FunctionDecl(name, func) => {
scope.functions.insert(name, *func);
scope.insert_fn(&name, *func);
}
Expr::Selector(s) => {
self.scope += 1;
@ -478,10 +478,10 @@ impl<'a> StyleSheetParser<'a> {
}
Expr::VariableDecl(name, val) => {
if self.scope == 0 {
scope.vars.insert(name.clone(), val.clone());
self.global_scope.vars.insert(name, val);
scope.insert_var(&name, val.clone());
self.global_scope.insert_var(&name, val);
} else {
scope.vars.insert(name, val);
scope.insert_var(&name, val);
}
}
Expr::Include(rules) => stmts.extend(rules),
@ -564,7 +564,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
toks.next();
devour_whitespace(toks);
let VariableDecl { val, default } = eat_variable_value(toks, scope)?;
if !default || scope.vars.get(&name).is_none() {
if !default || scope.get_var(&name).is_err() {
return Ok(Some(Expr::VariableDecl(name, val)));
}
} else {

View File

@ -82,7 +82,7 @@ impl Mixin {
None => arg.default.clone().expect("missing variable!"),
},
};
self.scope.vars.insert(arg.name.clone(), val);
self.scope.insert_var(&arg.name, val);
}
self
}
@ -110,7 +110,7 @@ impl Mixin {
}));
}
Expr::VariableDecl(name, val) => {
self.scope.vars.insert(name, val);
self.scope.insert_var(&name, val);
}
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
}
@ -155,8 +155,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
devour_whitespace(toks);
let mixin = match scope.mixins.get(&name) {
Some(m) => m.clone(),
let mixin = match scope.get_mixin(&name) {
Ok(m) => m.clone(),
_ => return Err((pos, String::from("Expected identifier."))),
};

View File

@ -52,7 +52,7 @@ pub(crate) fn parse_interpolation<I: Iterator<Item = Token>>(
todo!("invalid character in interpolation")
}
TokenKind::Variable(ref v) => val.extend(
Lexer::new(&scope.vars.get(v).unwrap().to_string()).collect::<Vec<Token>>(),
Lexer::new(&scope.get_var(v).unwrap().to_string()).collect::<Vec<Token>>(),
),
TokenKind::Interpolation => val.extend(parse_interpolation(tokens, scope)),
_ => val.push(tok),

View File

@ -197,9 +197,9 @@ impl Value {
}) => {
toks.next();
let args = eat_call_args(toks, scope);
let func = match scope.functions.get(&s) {
Some(f) => f,
None => match GLOBAL_FUNCTIONS.get(&s) {
let func = match scope.get_fn(&s) {
Ok(f) => f,
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
Some(f) => return f(&args),
None => todo!("called undefined function"),
},
@ -243,7 +243,7 @@ impl Value {
Some(Value::Ident(s, QuoteKind::Single))
}
TokenKind::Variable(ref v) => {
Some(scope.vars.get(v).expect("expected variable").clone())
Some(scope.get_var(v).expect("expected variable").clone())
}
TokenKind::Interpolation => {
let mut s = parse_interpolation(toks, scope)