Allow nested unknown @ rules
This commit is contained in:
parent
a6cc86e4db
commit
a3b260c0bd
@ -37,6 +37,7 @@ impl AtRule {
|
|||||||
pos: Pos,
|
pos: Pos,
|
||||||
toks: &mut Peekable<I>,
|
toks: &mut Peekable<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
|
super_selector: &Selector,
|
||||||
) -> SassResult<AtRule> {
|
) -> SassResult<AtRule> {
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
Ok(match rule {
|
Ok(match rule {
|
||||||
@ -116,7 +117,22 @@ impl AtRule {
|
|||||||
params.push_str(&tok.kind.to_string());
|
params.push_str(&tok.kind.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let body = eat_unknown_atrule_body(toks, scope, &Selector::new())?;
|
let raw_body = eat_unknown_atrule_body(toks, scope, super_selector)?;
|
||||||
|
let mut body = Vec::with_capacity(raw_body.len());
|
||||||
|
body.push(Stmt::RuleSet(RuleSet::new()));
|
||||||
|
let mut rules = Vec::new();
|
||||||
|
for stmt in raw_body {
|
||||||
|
match stmt {
|
||||||
|
s @ Stmt::Style(..) => rules.push(s),
|
||||||
|
s => body.push(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body[0] = Stmt::RuleSet(RuleSet {
|
||||||
|
selector: super_selector.clone(),
|
||||||
|
rules,
|
||||||
|
super_selector: Selector::new(),
|
||||||
|
});
|
||||||
|
|
||||||
let u = UnknownAtRule {
|
let u = UnknownAtRule {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
@ -140,6 +156,7 @@ fn eat_unknown_atrule_body<I: Iterator<Item = Token>>(
|
|||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(toks, scope, super_selector)? {
|
while let Some(expr) = eat_expr(toks, scope, super_selector)? {
|
||||||
match expr {
|
match expr {
|
||||||
|
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a)),
|
||||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||||
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
||||||
Expr::Include(s) => stmts.extend(s),
|
Expr::Include(s) => stmts.extend(s),
|
||||||
|
@ -82,7 +82,7 @@ impl Css {
|
|||||||
.get_mut(0)
|
.get_mut(0)
|
||||||
.expect("expected block to exist")
|
.expect("expected block to exist")
|
||||||
.push_comment(s),
|
.push_comment(s),
|
||||||
Stmt::AtRule(_) => todo!("at rule inside css block"),
|
Stmt::AtRule(r) => vals.push(Toplevel::AtRule(r)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
vals
|
vals
|
||||||
|
@ -4,6 +4,7 @@ use crate::args::{eat_func_args, CallArgs, FuncArgs};
|
|||||||
use crate::atrule::AtRule;
|
use crate::atrule::AtRule;
|
||||||
use crate::common::{Scope, Symbol};
|
use crate::common::{Scope, Symbol};
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
|
use crate::selector::Selector;
|
||||||
use crate::utils::devour_whitespace;
|
use crate::utils::devour_whitespace;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{Token, TokenKind};
|
use crate::{Token, TokenKind};
|
||||||
@ -47,9 +48,13 @@ impl Function {
|
|||||||
while nesting > 0 {
|
while nesting > 0 {
|
||||||
if let Some(tok) = toks.next() {
|
if let Some(tok) = toks.next() {
|
||||||
match &tok.kind {
|
match &tok.kind {
|
||||||
TokenKind::AtRule(rule) => {
|
TokenKind::AtRule(rule) => body.push(AtRule::from_tokens(
|
||||||
body.push(AtRule::from_tokens(rule, tok.pos, toks, scope)?)
|
rule,
|
||||||
}
|
tok.pos,
|
||||||
|
toks,
|
||||||
|
scope,
|
||||||
|
&Selector::new(),
|
||||||
|
)?),
|
||||||
TokenKind::Symbol(Symbol::CloseCurlyBrace) => nesting -= 1,
|
TokenKind::Symbol(Symbol::CloseCurlyBrace) => nesting -= 1,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
19
src/lib.rs
19
src/lib.rs
@ -213,6 +213,16 @@ pub(crate) struct RuleSet {
|
|||||||
super_selector: Selector,
|
super_selector: Selector,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RuleSet {
|
||||||
|
pub(crate) fn new() -> RuleSet {
|
||||||
|
RuleSet {
|
||||||
|
selector: Selector::new(),
|
||||||
|
rules: Vec::new(),
|
||||||
|
super_selector: Selector::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An intermediate representation of what are essentially single lines
|
/// An intermediate representation of what are essentially single lines
|
||||||
/// todo! rename this
|
/// todo! rename this
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -236,6 +246,7 @@ enum Expr {
|
|||||||
MultilineComment(String),
|
MultilineComment(String),
|
||||||
Debug(Pos, String),
|
Debug(Pos, String),
|
||||||
Warn(Pos, String),
|
Warn(Pos, String),
|
||||||
|
AtRule(AtRule),
|
||||||
// /// Function call: `calc(10vw - 1px)`
|
// /// Function call: `calc(10vw - 1px)`
|
||||||
// FuncCall(String, Vec<Token>),
|
// FuncCall(String, Vec<Token>),
|
||||||
}
|
}
|
||||||
@ -437,7 +448,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
pos,
|
pos,
|
||||||
}) = self.lexer.next()
|
}) = self.lexer.next()
|
||||||
{
|
{
|
||||||
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope)? {
|
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope, &Selector::new())? {
|
||||||
AtRule::Mixin(name, mixin) => {
|
AtRule::Mixin(name, mixin) => {
|
||||||
self.global_scope.insert_mixin(&name, *mixin);
|
self.global_scope.insert_mixin(&name, *mixin);
|
||||||
}
|
}
|
||||||
@ -476,7 +487,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector)? {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||||
#[allow(clippy::redundant_closure)]
|
Expr::AtRule(s) => stmts.push(Stmt::AtRule(s)),
|
||||||
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.insert_mixin(&name, *mixin);
|
scope.insert_mixin(&name, *mixin);
|
||||||
@ -623,7 +634,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
pos,
|
pos,
|
||||||
}) = toks.next()
|
}) = toks.next()
|
||||||
{
|
{
|
||||||
return match AtRule::from_tokens(rule, pos, toks, scope)? {
|
return match AtRule::from_tokens(rule, pos, toks, scope, &super_selector)? {
|
||||||
AtRule::Mixin(name, mixin) => Ok(Some(Expr::MixinDecl(name, mixin))),
|
AtRule::Mixin(name, mixin) => Ok(Some(Expr::MixinDecl(name, mixin))),
|
||||||
AtRule::Function(name, func) => Ok(Some(Expr::FunctionDecl(name, func))),
|
AtRule::Function(name, func) => Ok(Some(Expr::FunctionDecl(name, func))),
|
||||||
AtRule::Charset(_) => todo!("@charset as expr"),
|
AtRule::Charset(_) => todo!("@charset as expr"),
|
||||||
@ -631,7 +642,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
|
||||||
AtRule::Error(pos, err) => Err(SassError::new(err, pos)),
|
AtRule::Error(pos, err) => Err(SassError::new(err, pos)),
|
||||||
AtRule::Return(_) => todo!("@return in unexpected location!"),
|
AtRule::Return(_) => todo!("@return in unexpected location!"),
|
||||||
AtRule::Unknown(..) => todo!("nested media queries not yet implemented"),
|
u @ AtRule::Unknown(..) => Ok(Some(Expr::AtRule(u))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,7 @@ impl Mixin {
|
|||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(&mut self.body, &self.scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.body, &self.scope, super_selector)? {
|
||||||
match expr {
|
match expr {
|
||||||
|
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a)),
|
||||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||||
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
|
||||||
Expr::Include(s) => stmts.extend(s),
|
Expr::Include(s) => stmts.extend(s),
|
||||||
|
@ -335,6 +335,8 @@ impl Selector {
|
|||||||
pub fn zip(&self, other: &Selector) -> Selector {
|
pub fn zip(&self, other: &Selector) -> Selector {
|
||||||
if self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
return Selector(other.0.clone());
|
return Selector(other.0.clone());
|
||||||
|
} else if other.0.is_empty() {
|
||||||
|
return self.clone();
|
||||||
}
|
}
|
||||||
let mut rules: Vec<SelectorKind> = Vec::with_capacity(self.0.len() + other.0.len());
|
let mut rules: Vec<SelectorKind> = Vec::with_capacity(self.0.len() + other.0.len());
|
||||||
let sel1_split: Vec<&[SelectorKind]> =
|
let sel1_split: Vec<&[SelectorKind]> =
|
||||||
|
@ -7,3 +7,8 @@ test!(
|
|||||||
basic_toplevel,
|
basic_toplevel,
|
||||||
"@media foo {\n a {\n color: red;\n }\n}\n"
|
"@media foo {\n a {\n color: red;\n }\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
basic_nested,
|
||||||
|
"a {\n @media foo {\n color: red;\n }\n}\n",
|
||||||
|
"@media foo {\n a {\n color: red;\n }\n}\n"
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user