Treat - and _ as the same in identifiers
This commit is contained in:
parent
783e43b765
commit
fa582b3316
@ -144,11 +144,11 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
toks.next();
|
toks.next();
|
||||||
match name {
|
match name {
|
||||||
Some(ref 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(
|
None => args.insert(
|
||||||
format!("{}", args.len()),
|
format!("{}", args.len()),
|
||||||
scope.vars.get(&v).unwrap().clone(),
|
scope.get_var(&v).unwrap().clone(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
if let Some(ref mut s) = name {
|
if let Some(ref mut s) = name {
|
||||||
@ -162,10 +162,10 @@ pub(crate) fn eat_call_args<I: Iterator<Item = Token>>(
|
|||||||
}) => {
|
}) => {
|
||||||
toks.next();
|
toks.next();
|
||||||
match name {
|
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(
|
None => args.insert(
|
||||||
format!("{}", args.len()),
|
format!("{}", args.len()),
|
||||||
scope.vars.get(&v).unwrap().clone(),
|
scope.get_var(&v).unwrap().clone(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
@ -342,9 +342,9 @@ impl Display for Pos {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct Scope {
|
pub(crate) struct Scope {
|
||||||
pub vars: HashMap<String, Value>,
|
vars: HashMap<String, Value>,
|
||||||
pub mixins: HashMap<String, Mixin>,
|
mixins: HashMap<String, Mixin>,
|
||||||
pub functions: HashMap<String, Function>,
|
functions: HashMap<String, Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
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.vars.extend(other.vars);
|
||||||
self.mixins.extend(other.mixins);
|
self.mixins.extend(other.mixins);
|
||||||
self.functions.extend(other.functions);
|
self.functions.extend(other.functions);
|
||||||
|
@ -75,7 +75,7 @@ impl Function {
|
|||||||
None => arg.default.clone().expect("missing variable!"),
|
None => arg.default.clone().expect("missing variable!"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.scope.vars.insert(arg.name.clone(), val);
|
self.scope.insert_var(&arg.name, val);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ pub(crate) fn import<P: AsRef<Path>>(path: P) -> SassResult<(Vec<Stmt>, Scope)>
|
|||||||
let (rules2, scope2) =
|
let (rules2, scope2) =
|
||||||
StyleSheet::export_from_path(name.to_str().expect("path should be UTF-8"))?;
|
StyleSheet::export_from_path(name.to_str().expect("path should be UTF-8"))?;
|
||||||
rules.extend(rules2);
|
rules.extend(rules2);
|
||||||
scope.merge(scope2);
|
scope.extend(scope2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((rules, scope))
|
Ok((rules, scope))
|
||||||
|
22
src/lib.rs
22
src/lib.rs
@ -353,8 +353,8 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
}
|
}
|
||||||
let VariableDecl { val, default } = eat_variable_value(&mut self.lexer, &self.global_scope)
|
let VariableDecl { val, default } = eat_variable_value(&mut self.lexer, &self.global_scope)
|
||||||
.unwrap_or_else(|err| self.error(err.0, &err.1));
|
.unwrap_or_else(|err| self.error(err.0, &err.1));
|
||||||
if !default || self.global_scope.vars.get(&name).is_none() {
|
if !default || self.global_scope.get_var(&name).is_err() {
|
||||||
self.global_scope.vars.insert(name, val);
|
self.global_scope.insert_var(&name, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::MultilineComment(_) => {
|
TokenKind::MultilineComment(_) => {
|
||||||
@ -413,7 +413,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
|
|
||||||
let (new_rules, new_scope) = import(file_name)?;
|
let (new_rules, new_scope) = import(file_name)?;
|
||||||
rules.extend(new_rules);
|
rules.extend(new_rules);
|
||||||
self.global_scope.merge(new_scope);
|
self.global_scope.extend(new_scope);
|
||||||
}
|
}
|
||||||
TokenKind::AtRule(_) => {
|
TokenKind::AtRule(_) => {
|
||||||
if let Some(Token {
|
if let Some(Token {
|
||||||
@ -423,10 +423,10 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
{
|
{
|
||||||
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope) {
|
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope) {
|
||||||
AtRule::Mixin(name, mixin) => {
|
AtRule::Mixin(name, mixin) => {
|
||||||
self.global_scope.mixins.insert(name, *mixin);
|
self.global_scope.insert_mixin(&name, *mixin);
|
||||||
}
|
}
|
||||||
AtRule::Function(name, func) => {
|
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::Charset(toks) => rules.push(Stmt::AtRule(AtRule::Charset(toks))),
|
||||||
AtRule::Error(pos, message) => self.error(pos, &message),
|
AtRule::Error(pos, message) => self.error(pos, &message),
|
||||||
@ -458,10 +458,10 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
#[allow(clippy::redundant_closure)]
|
#[allow(clippy::redundant_closure)]
|
||||||
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
||||||
Expr::MixinDecl(name, mixin) => {
|
Expr::MixinDecl(name, mixin) => {
|
||||||
scope.mixins.insert(name, *mixin);
|
scope.insert_mixin(&name, *mixin);
|
||||||
}
|
}
|
||||||
Expr::FunctionDecl(name, func) => {
|
Expr::FunctionDecl(name, func) => {
|
||||||
scope.functions.insert(name, *func);
|
scope.insert_fn(&name, *func);
|
||||||
}
|
}
|
||||||
Expr::Selector(s) => {
|
Expr::Selector(s) => {
|
||||||
self.scope += 1;
|
self.scope += 1;
|
||||||
@ -478,10 +478,10 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
}
|
}
|
||||||
Expr::VariableDecl(name, val) => {
|
Expr::VariableDecl(name, val) => {
|
||||||
if self.scope == 0 {
|
if self.scope == 0 {
|
||||||
scope.vars.insert(name.clone(), val.clone());
|
scope.insert_var(&name, val.clone());
|
||||||
self.global_scope.vars.insert(name, val);
|
self.global_scope.insert_var(&name, val);
|
||||||
} else {
|
} else {
|
||||||
scope.vars.insert(name, val);
|
scope.insert_var(&name, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Include(rules) => stmts.extend(rules),
|
Expr::Include(rules) => stmts.extend(rules),
|
||||||
@ -564,7 +564,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
toks.next();
|
toks.next();
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let VariableDecl { val, default } = eat_variable_value(toks, scope)?;
|
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)));
|
return Ok(Some(Expr::VariableDecl(name, val)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -82,7 +82,7 @@ impl Mixin {
|
|||||||
None => arg.default.clone().expect("missing variable!"),
|
None => arg.default.clone().expect("missing variable!"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.scope.vars.insert(arg.name.clone(), val);
|
self.scope.insert_var(&arg.name, val);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ impl Mixin {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Expr::VariableDecl(name, val) => {
|
Expr::VariableDecl(name, val) => {
|
||||||
self.scope.vars.insert(name, val);
|
self.scope.insert_var(&name, val);
|
||||||
}
|
}
|
||||||
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
|
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
|
||||||
}
|
}
|
||||||
@ -155,8 +155,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let mixin = match scope.mixins.get(&name) {
|
let mixin = match scope.get_mixin(&name) {
|
||||||
Some(m) => m.clone(),
|
Ok(m) => m.clone(),
|
||||||
_ => return Err((pos, String::from("Expected identifier."))),
|
_ => return Err((pos, String::from("Expected identifier."))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ pub(crate) fn parse_interpolation<I: Iterator<Item = Token>>(
|
|||||||
todo!("invalid character in interpolation")
|
todo!("invalid character in interpolation")
|
||||||
}
|
}
|
||||||
TokenKind::Variable(ref v) => val.extend(
|
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)),
|
TokenKind::Interpolation => val.extend(parse_interpolation(tokens, scope)),
|
||||||
_ => val.push(tok),
|
_ => val.push(tok),
|
||||||
|
@ -197,9 +197,9 @@ impl Value {
|
|||||||
}) => {
|
}) => {
|
||||||
toks.next();
|
toks.next();
|
||||||
let args = eat_call_args(toks, scope);
|
let args = eat_call_args(toks, scope);
|
||||||
let func = match scope.functions.get(&s) {
|
let func = match scope.get_fn(&s) {
|
||||||
Some(f) => f,
|
Ok(f) => f,
|
||||||
None => match GLOBAL_FUNCTIONS.get(&s) {
|
Err(_) => match GLOBAL_FUNCTIONS.get(&s) {
|
||||||
Some(f) => return f(&args),
|
Some(f) => return f(&args),
|
||||||
None => todo!("called undefined function"),
|
None => todo!("called undefined function"),
|
||||||
},
|
},
|
||||||
@ -243,7 +243,7 @@ impl Value {
|
|||||||
Some(Value::Ident(s, QuoteKind::Single))
|
Some(Value::Ident(s, QuoteKind::Single))
|
||||||
}
|
}
|
||||||
TokenKind::Variable(ref v) => {
|
TokenKind::Variable(ref v) => {
|
||||||
Some(scope.vars.get(v).expect("expected variable").clone())
|
Some(scope.get_var(v).expect("expected variable").clone())
|
||||||
}
|
}
|
||||||
TokenKind::Interpolation => {
|
TokenKind::Interpolation => {
|
||||||
let mut s = parse_interpolation(toks, scope)
|
let mut s = parse_interpolation(toks, scope)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user