disallow standalone @else
This commit is contained in:
parent
3c1c55038f
commit
3051cec45a
@ -1,3 +1,9 @@
|
|||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use codemap::Spanned;
|
||||||
|
|
||||||
|
use crate::error::SassError;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum AtRuleKind {
|
pub enum AtRuleKind {
|
||||||
// SASS specific @rules
|
// SASS specific @rules
|
||||||
@ -57,9 +63,10 @@ pub enum AtRuleKind {
|
|||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for AtRuleKind {
|
impl TryFrom<&Spanned<String>> for AtRuleKind {
|
||||||
fn from(c: &str) -> Self {
|
type Error = SassError;
|
||||||
match c.to_ascii_lowercase().as_str() {
|
fn try_from(c: &Spanned<String>) -> Result<Self, SassError> {
|
||||||
|
Ok(match c.node.to_ascii_lowercase().as_str() {
|
||||||
"use" => Self::Use,
|
"use" => Self::Use,
|
||||||
"forward" => Self::Forward,
|
"forward" => Self::Forward,
|
||||||
"import" => Self::Import,
|
"import" => Self::Import,
|
||||||
@ -81,7 +88,9 @@ impl From<&str> for AtRuleKind {
|
|||||||
"keyframes" => Self::Keyframes,
|
"keyframes" => Self::Keyframes,
|
||||||
"content" => Self::Content,
|
"content" => Self::Content,
|
||||||
"media" => Self::Media,
|
"media" => Self::Media,
|
||||||
|
"else" => return Err(("This at-rule is not allowed here.", c.span).into()),
|
||||||
|
"" => return Err(("Expected identifier.", c.span).into()),
|
||||||
s => Self::Unknown(s.to_owned()),
|
s => Self::Unknown(s.to_owned()),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ grass input.scss
|
|||||||
#![cfg_attr(feature = "nightly", feature(track_caller))]
|
#![cfg_attr(feature = "nightly", feature(track_caller))]
|
||||||
#![cfg_attr(feature = "profiling", inline(never))]
|
#![cfg_attr(feature = "profiling", inline(never))]
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use codemap::{Span, Spanned};
|
use codemap::{Span, Spanned};
|
||||||
@ -337,10 +338,10 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
}
|
}
|
||||||
'@' => {
|
'@' => {
|
||||||
let span = toks.next().unwrap().pos();
|
let span = toks.next().unwrap().pos();
|
||||||
let Spanned { node: ident, span } = eat_ident(toks, scope, super_selector, span)?;
|
let rule = eat_ident(toks, scope, super_selector, span)?;
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
let rule = AtRule::from_tokens(
|
let rule = AtRule::from_tokens(
|
||||||
AtRuleKind::from(ident.as_str()),
|
AtRuleKind::try_from(&rule)?,
|
||||||
span,
|
span,
|
||||||
toks,
|
toks,
|
||||||
scope,
|
scope,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::convert::TryFrom;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -226,20 +227,14 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
}
|
}
|
||||||
'@' => {
|
'@' => {
|
||||||
let span_before = self.lexer.next().unwrap().pos();
|
let span_before = self.lexer.next().unwrap().pos();
|
||||||
let Spanned {
|
let rule = eat_ident(self.lexer, &Scope::new(), &Selector::new(), span_before)?;
|
||||||
node: at_rule_kind,
|
match AtRuleKind::try_from(&rule)? {
|
||||||
span,
|
|
||||||
} = eat_ident(self.lexer, &Scope::new(), &Selector::new(), span_before)?;
|
|
||||||
if at_rule_kind.is_empty() {
|
|
||||||
return Err(("Expected identifier.", span).into());
|
|
||||||
}
|
|
||||||
match AtRuleKind::from(at_rule_kind.as_str()) {
|
|
||||||
AtRuleKind::Include => rules.extend(eat_include(
|
AtRuleKind::Include => rules.extend(eat_include(
|
||||||
self.lexer,
|
self.lexer,
|
||||||
&Scope::new(),
|
&Scope::new(),
|
||||||
&Selector::new(),
|
&Selector::new(),
|
||||||
None,
|
None,
|
||||||
span,
|
rule.span,
|
||||||
)?),
|
)?),
|
||||||
AtRuleKind::Import => {
|
AtRuleKind::Import => {
|
||||||
devour_whitespace(self.lexer);
|
devour_whitespace(self.lexer);
|
||||||
@ -259,7 +254,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
)?
|
)?
|
||||||
.node
|
.node
|
||||||
.unquote()
|
.unquote()
|
||||||
.to_css_string(span)?,
|
.to_css_string(rule.span)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => return Err(("Expected string.", next.pos()).into()),
|
_ => return Err(("Expected string.", next.pos()).into()),
|
||||||
@ -282,7 +277,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
v => {
|
v => {
|
||||||
let rule = AtRule::from_tokens(
|
let rule = AtRule::from_tokens(
|
||||||
v,
|
v,
|
||||||
span,
|
rule.span,
|
||||||
self.lexer,
|
self.lexer,
|
||||||
&mut Scope::new(),
|
&mut Scope::new(),
|
||||||
&Selector::new(),
|
&Selector::new(),
|
||||||
|
@ -200,4 +200,11 @@ error!(value_after_style, "a {}a", "Error: expected \"{\".");
|
|||||||
test!(whitespace_after_style, "a {}\t\n ", "");
|
test!(whitespace_after_style, "a {}\t\n ", "");
|
||||||
test!(toplevel_semicolon, ";", "");
|
test!(toplevel_semicolon, ";", "");
|
||||||
test!(toplevel_semicolon_after_style, "a {};", "");
|
test!(toplevel_semicolon_after_style, "a {};", "");
|
||||||
error!(nothing_after_hash_in_interpolated_ident_body, "a {color: foo#", "Error: Expected identifier.");
|
error!(
|
||||||
|
nothing_after_hash_in_interpolated_ident_body,
|
||||||
|
"a {color: foo#", "Error: Expected identifier."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
at_else_alone,
|
||||||
|
"@else {}", "Error: This at-rule is not allowed here."
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user