allow @content in more contexts
This commit is contained in:
parent
6f57797c29
commit
3615835e03
@ -26,6 +26,7 @@ impl Each {
|
|||||||
self,
|
self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
for row in self.iter {
|
for row in self.iter {
|
||||||
@ -77,6 +78,7 @@ impl Each {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
content,
|
||||||
&mut stmts,
|
&mut stmts,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ impl For {
|
|||||||
self,
|
self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
for i in self.iter {
|
for i in self.iter {
|
||||||
@ -47,6 +48,7 @@ impl For {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
content,
|
||||||
&mut stmts,
|
&mut stmts,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ impl Function {
|
|||||||
&mut self.scope,
|
&mut self.scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +154,7 @@ impl Function {
|
|||||||
&mut self.scope,
|
&mut self.scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
if let Some(v) = self.call(super_selector, for_stmts)? {
|
if let Some(v) = self.call(super_selector, for_stmts)? {
|
||||||
return Ok(Some(v));
|
return Ok(Some(v));
|
||||||
@ -160,7 +162,7 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::AtRule(AtRule::If(i)) => {
|
Stmt::AtRule(AtRule::If(i)) => {
|
||||||
let if_stmts = i.eval(&mut self.scope, super_selector)?;
|
let if_stmts = i.eval(&mut self.scope, super_selector, None)?;
|
||||||
if let Some(v) = self.call(super_selector, if_stmts)? {
|
if let Some(v) = self.call(super_selector, if_stmts)? {
|
||||||
return Ok(Some(v));
|
return Ok(Some(v));
|
||||||
}
|
}
|
||||||
@ -174,6 +176,7 @@ impl Function {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
if let Some(v) = self.call(super_selector, while_stmts)? {
|
if let Some(v) = self.call(super_selector, while_stmts)? {
|
||||||
return Ok(Some(v));
|
return Ok(Some(v));
|
||||||
|
@ -105,6 +105,7 @@ impl If {
|
|||||||
self,
|
self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
let mut toks = Vec::new();
|
let mut toks = Vec::new();
|
||||||
@ -125,6 +126,7 @@ impl If {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
|
content,
|
||||||
&mut stmts,
|
&mut stmts,
|
||||||
)?;
|
)?;
|
||||||
Ok(stmts)
|
Ok(stmts)
|
||||||
|
@ -22,23 +22,12 @@ pub(crate) struct Mixin {
|
|||||||
scope: Scope,
|
scope: Scope,
|
||||||
args: FuncArgs,
|
args: FuncArgs,
|
||||||
body: PeekMoreIterator<IntoIter<Token>>,
|
body: PeekMoreIterator<IntoIter<Token>>,
|
||||||
content: Vec<Spanned<Stmt>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mixin {
|
impl Mixin {
|
||||||
pub fn new(
|
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Token>) -> Self {
|
||||||
scope: Scope,
|
|
||||||
args: FuncArgs,
|
|
||||||
body: Vec<Token>,
|
|
||||||
content: Vec<Spanned<Stmt>>,
|
|
||||||
) -> Self {
|
|
||||||
let body = body.into_iter().peekmore();
|
let body = body.into_iter().peekmore();
|
||||||
Mixin {
|
Mixin { scope, args, body }
|
||||||
scope,
|
|
||||||
args,
|
|
||||||
body,
|
|
||||||
content,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
pub fn decl_from_tokens<I: Iterator<Item = Token>>(
|
||||||
@ -62,16 +51,11 @@ impl Mixin {
|
|||||||
body.push(toks.next().unwrap());
|
body.push(toks.next().unwrap());
|
||||||
|
|
||||||
Ok(Spanned {
|
Ok(Spanned {
|
||||||
node: (name, Mixin::new(scope.clone(), args, body, Vec::new())),
|
node: (name, Mixin::new(scope.clone(), args, body)),
|
||||||
span,
|
span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(mut self, content: Vec<Spanned<Stmt>>) -> Mixin {
|
|
||||||
self.content = content;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn args(
|
pub fn args(
|
||||||
mut self,
|
mut self,
|
||||||
mut args: CallArgs,
|
mut args: CallArgs,
|
||||||
@ -113,28 +97,43 @@ impl Mixin {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(mut self, super_selector: &Selector) -> SassResult<Vec<Spanned<Stmt>>> {
|
pub fn call(
|
||||||
self.eval(super_selector)
|
mut self,
|
||||||
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
|
self.eval(super_selector, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, super_selector: &Selector) -> SassResult<Vec<Spanned<Stmt>>> {
|
fn eval(
|
||||||
|
&mut self,
|
||||||
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(&mut self.body, &mut self.scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.body, &mut self.scope, super_selector, content)? {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
Expr::AtRule(a) => match a {
|
Expr::AtRule(a) => match a {
|
||||||
AtRule::For(f) => {
|
AtRule::For(f) => {
|
||||||
stmts.extend(f.ruleset_eval(&mut self.scope, super_selector)?)
|
stmts.extend(f.ruleset_eval(&mut self.scope, super_selector, content)?)
|
||||||
}
|
}
|
||||||
AtRule::Each(e) => {
|
AtRule::Each(e) => {
|
||||||
stmts.extend(e.ruleset_eval(&mut self.scope, super_selector)?)
|
stmts.extend(e.ruleset_eval(&mut self.scope, super_selector, content)?)
|
||||||
}
|
|
||||||
AtRule::While(w) => {
|
|
||||||
stmts.extend(w.ruleset_eval(&mut self.scope, super_selector, false)?)
|
|
||||||
}
|
}
|
||||||
|
AtRule::While(w) => stmts.extend(w.ruleset_eval(
|
||||||
|
&mut self.scope,
|
||||||
|
super_selector,
|
||||||
|
false,
|
||||||
|
content,
|
||||||
|
)?),
|
||||||
AtRule::Include(s) => stmts.extend(s),
|
AtRule::Include(s) => stmts.extend(s),
|
||||||
AtRule::If(i) => stmts.extend(i.eval(&mut self.scope.clone(), super_selector)?),
|
AtRule::If(i) => {
|
||||||
AtRule::Content => stmts.extend(self.content.clone()),
|
stmts.extend(i.eval(&mut self.scope.clone(), super_selector, content)?)
|
||||||
|
}
|
||||||
|
AtRule::Content => {
|
||||||
|
stmts.extend(content.unwrap_or_default().into_iter().cloned());
|
||||||
|
}
|
||||||
AtRule::Return(..) => {
|
AtRule::Return(..) => {
|
||||||
return Err(("This at-rule is not allowed here.", span).into())
|
return Err(("This at-rule is not allowed here.", span).into())
|
||||||
}
|
}
|
||||||
@ -161,7 +160,7 @@ impl Mixin {
|
|||||||
return Err(("Mixins may not contain mixin declarations.", span).into())
|
return Err(("Mixins may not contain mixin declarations.", span).into())
|
||||||
}
|
}
|
||||||
Expr::Selector(selector) => {
|
Expr::Selector(selector) => {
|
||||||
let rules = self.eval(&super_selector.zip(&selector))?;
|
let rules = self.eval(&super_selector.zip(&selector), content)?;
|
||||||
stmts.push(Spanned {
|
stmts.push(Spanned {
|
||||||
node: Stmt::RuleSet(RuleSet {
|
node: Stmt::RuleSet(RuleSet {
|
||||||
super_selector: super_selector.clone(),
|
super_selector: super_selector.clone(),
|
||||||
@ -188,6 +187,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
devour_whitespace_or_comment(toks)?;
|
devour_whitespace_or_comment(toks)?;
|
||||||
let name = eat_ident(toks, scope, super_selector)?;
|
let name = eat_ident(toks, scope, super_selector)?;
|
||||||
@ -223,7 +223,7 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
|
|
||||||
let mut content = Vec::new();
|
let mut this_content = Vec::new();
|
||||||
|
|
||||||
if let Some(tok) = toks.peek() {
|
if let Some(tok) = toks.peek() {
|
||||||
if tok.kind == '{' {
|
if tok.kind == '{' {
|
||||||
@ -233,7 +233,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
&mut scope.clone(),
|
&mut scope.clone(),
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
&mut content,
|
content,
|
||||||
|
&mut this_content,
|
||||||
)?;
|
)?;
|
||||||
} else if has_content {
|
} else if has_content {
|
||||||
ruleset_eval(
|
ruleset_eval(
|
||||||
@ -241,7 +242,8 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
&mut scope.clone(),
|
&mut scope.clone(),
|
||||||
super_selector,
|
super_selector,
|
||||||
false,
|
false,
|
||||||
&mut content,
|
content,
|
||||||
|
&mut this_content,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,7 +252,6 @@ pub(crate) fn eat_include<I: Iterator<Item = Token>>(
|
|||||||
|
|
||||||
let rules = mixin
|
let rules = mixin
|
||||||
.args(args, scope, super_selector)?
|
.args(args, scope, super_selector)?
|
||||||
.content(content)
|
.call(super_selector, Some(&this_content))?;
|
||||||
.call(super_selector)?;
|
|
||||||
Ok(rules)
|
Ok(rules)
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ impl AtRule {
|
|||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Spanned<AtRule>> {
|
) -> SassResult<Spanned<AtRule>> {
|
||||||
devour_whitespace(toks);
|
devour_whitespace(toks);
|
||||||
Ok(match rule {
|
Ok(match rule {
|
||||||
@ -170,6 +171,7 @@ impl AtRule {
|
|||||||
selector,
|
selector,
|
||||||
0,
|
0,
|
||||||
is_some,
|
is_some,
|
||||||
|
content,
|
||||||
)?
|
)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|s| match s.node {
|
.filter_map(|s| match s.node {
|
||||||
@ -225,6 +227,7 @@ impl AtRule {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
kind_span,
|
kind_span,
|
||||||
|
content,
|
||||||
)?),
|
)?),
|
||||||
span: kind_span,
|
span: kind_span,
|
||||||
},
|
},
|
||||||
@ -233,7 +236,7 @@ impl AtRule {
|
|||||||
span: kind_span,
|
span: kind_span,
|
||||||
},
|
},
|
||||||
AtRuleKind::Include => Spanned {
|
AtRuleKind::Include => Spanned {
|
||||||
node: AtRule::Include(eat_include(toks, scope, super_selector)?),
|
node: AtRule::Include(eat_include(toks, scope, super_selector, content)?),
|
||||||
span: kind_span,
|
span: kind_span,
|
||||||
},
|
},
|
||||||
AtRuleKind::Import => todo!("@import not yet implemented"),
|
AtRuleKind::Import => todo!("@import not yet implemented"),
|
||||||
|
@ -14,9 +14,10 @@ pub(crate) fn eat_stmts<I: Iterator<Item = Token>>(
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
at_root: bool,
|
at_root: bool,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
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, content)? {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a).span(span)),
|
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a).span(span)),
|
||||||
@ -29,7 +30,13 @@ pub(crate) fn eat_stmts<I: Iterator<Item = Token>>(
|
|||||||
),
|
),
|
||||||
Expr::MixinDecl(..) | Expr::FunctionDecl(..) => todo!(),
|
Expr::MixinDecl(..) | Expr::FunctionDecl(..) => todo!(),
|
||||||
Expr::Selector(selector) => {
|
Expr::Selector(selector) => {
|
||||||
let rules = eat_stmts(toks, scope, &super_selector.zip(&selector), at_root)?;
|
let rules = eat_stmts(
|
||||||
|
toks,
|
||||||
|
scope,
|
||||||
|
&super_selector.zip(&selector),
|
||||||
|
at_root,
|
||||||
|
content,
|
||||||
|
)?;
|
||||||
stmts.push(
|
stmts.push(
|
||||||
Stmt::RuleSet(RuleSet {
|
Stmt::RuleSet(RuleSet {
|
||||||
super_selector: super_selector.clone(),
|
super_selector: super_selector.clone(),
|
||||||
@ -58,9 +65,10 @@ pub(crate) fn eat_stmts_at_root<I: Iterator<Item = Token>>(
|
|||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
mut nesting: usize,
|
mut nesting: usize,
|
||||||
is_some: bool,
|
is_some: bool,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
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, content)? {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a).span(span)),
|
Expr::AtRule(a) => stmts.push(Stmt::AtRule(a).span(span)),
|
||||||
@ -79,7 +87,7 @@ pub(crate) fn eat_stmts_at_root<I: Iterator<Item = Token>>(
|
|||||||
selector = Selector::replace(super_selector, selector);
|
selector = Selector::replace(super_selector, selector);
|
||||||
}
|
}
|
||||||
nesting += 1;
|
nesting += 1;
|
||||||
let rules = eat_stmts_at_root(toks, scope, &selector, nesting, true)?;
|
let rules = eat_stmts_at_root(toks, scope, &selector, nesting, true, content)?;
|
||||||
nesting -= 1;
|
nesting -= 1;
|
||||||
stmts.push(
|
stmts.push(
|
||||||
Stmt::RuleSet(RuleSet {
|
Stmt::RuleSet(RuleSet {
|
||||||
@ -108,18 +116,34 @@ pub(crate) fn ruleset_eval<I: Iterator<Item = Token>>(
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
at_root: bool,
|
at_root: bool,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
stmts: &mut Vec<Spanned<Stmt>>,
|
stmts: &mut Vec<Spanned<Stmt>>,
|
||||||
) -> SassResult<()> {
|
) -> SassResult<()> {
|
||||||
for stmt in eat_stmts(toks, scope, super_selector, at_root)? {
|
for stmt in eat_stmts(toks, scope, super_selector, at_root, content)? {
|
||||||
match stmt.node {
|
match stmt.node {
|
||||||
Stmt::AtRule(AtRule::For(f)) => stmts.extend(f.ruleset_eval(scope, super_selector)?),
|
Stmt::AtRule(AtRule::For(f)) => {
|
||||||
Stmt::AtRule(AtRule::Each(e)) => stmts.extend(e.ruleset_eval(scope, super_selector)?),
|
stmts.extend(f.ruleset_eval(scope, super_selector, content)?)
|
||||||
|
}
|
||||||
|
Stmt::AtRule(AtRule::Each(e)) => {
|
||||||
|
stmts.extend(e.ruleset_eval(scope, super_selector, content)?)
|
||||||
|
}
|
||||||
Stmt::AtRule(AtRule::While(w)) => {
|
Stmt::AtRule(AtRule::While(w)) => {
|
||||||
// TODO: should at_root be false? scoping
|
// TODO: should at_root be false? scoping
|
||||||
stmts.extend(w.ruleset_eval(scope, super_selector, at_root)?)
|
stmts.extend(w.ruleset_eval(scope, super_selector, at_root, content)?)
|
||||||
}
|
}
|
||||||
Stmt::AtRule(AtRule::Include(s)) => stmts.extend(s),
|
Stmt::AtRule(AtRule::Include(s)) => stmts.extend(s),
|
||||||
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector, content)?),
|
||||||
|
Stmt::AtRule(AtRule::Content) => {
|
||||||
|
if let Some(c) = content {
|
||||||
|
stmts.extend(c.into_iter().cloned());
|
||||||
|
} else {
|
||||||
|
return Err((
|
||||||
|
"@content is only allowed within mixin declarations.",
|
||||||
|
stmt.span,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => stmts.push(stmt),
|
_ => stmts.push(stmt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use codemap::{Span, Spanned};
|
|||||||
|
|
||||||
use peekmore::PeekMoreIterator;
|
use peekmore::PeekMoreIterator;
|
||||||
|
|
||||||
use super::parse::eat_stmts;
|
use super::parse::ruleset_eval;
|
||||||
use crate::error::SassResult;
|
use crate::error::SassResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::selector::Selector;
|
use crate::selector::Selector;
|
||||||
@ -24,6 +24,7 @@ impl UnknownAtRule {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
kind_span: Span,
|
kind_span: Span,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<UnknownAtRule> {
|
) -> SassResult<UnknownAtRule> {
|
||||||
let mut params = String::new();
|
let mut params = String::new();
|
||||||
while let Some(tok) = toks.next() {
|
while let Some(tok) = toks.next() {
|
||||||
@ -49,7 +50,8 @@ impl UnknownAtRule {
|
|||||||
params.push(tok.kind);
|
params.push(tok.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw_body = eat_stmts(toks, scope, super_selector, false)?;
|
let mut raw_body = Vec::new();
|
||||||
|
ruleset_eval(toks, scope, super_selector, false, content, &mut raw_body)?;
|
||||||
let mut rules = Vec::with_capacity(raw_body.len());
|
let mut rules = Vec::with_capacity(raw_body.len());
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ impl While {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
at_root: bool,
|
at_root: bool,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
let mut val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
let mut val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
||||||
@ -35,6 +36,7 @@ impl While {
|
|||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
at_root,
|
at_root,
|
||||||
|
content,
|
||||||
&mut stmts,
|
&mut stmts,
|
||||||
)?;
|
)?;
|
||||||
val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
||||||
|
23
src/lib.rs
23
src/lib.rs
@ -359,6 +359,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
&mut self.lexer,
|
&mut self.lexer,
|
||||||
&Scope::new(),
|
&Scope::new(),
|
||||||
&Selector::new(),
|
&Selector::new(),
|
||||||
|
None,
|
||||||
)?),
|
)?),
|
||||||
AtRuleKind::Import => {
|
AtRuleKind::Import => {
|
||||||
devour_whitespace(&mut self.lexer);
|
devour_whitespace(&mut self.lexer);
|
||||||
@ -394,7 +395,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
v => {
|
v => {
|
||||||
let rule = AtRule::from_tokens(&v, span, &mut self.lexer, &mut Scope::new(), &Selector::new())?;
|
let rule = AtRule::from_tokens(&v, span, &mut self.lexer, &mut Scope::new(), &Selector::new(), None)?;
|
||||||
match rule.node {
|
match rule.node {
|
||||||
AtRule::Mixin(name, mixin) => {
|
AtRule::Mixin(name, mixin) => {
|
||||||
insert_global_mixin(&name, *mixin);
|
insert_global_mixin(&name, *mixin);
|
||||||
@ -410,17 +411,17 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
("This at-rule is not allowed here.", rule.span).into()
|
("This at-rule is not allowed here.", rule.span).into()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AtRule::For(f) => rules.extend(f.ruleset_eval(&mut Scope::new(), &Selector::new())?),
|
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)?),
|
AtRule::While(w) => rules.extend(w.ruleset_eval(&mut Scope::new(), &Selector::new(), true, None)?),
|
||||||
AtRule::Each(e) => {
|
AtRule::Each(e) => {
|
||||||
rules.extend(e.ruleset_eval(&mut Scope::new(), &Selector::new())?)
|
rules.extend(e.ruleset_eval(&mut Scope::new(), &Selector::new(), None)?)
|
||||||
}
|
}
|
||||||
AtRule::Include(s) => rules.extend(s),
|
AtRule::Include(s) => rules.extend(s),
|
||||||
AtRule::Content => return Err(
|
AtRule::Content => return Err(
|
||||||
("@content is only allowed within mixin declarations.", rule.span
|
("@content is only allowed within mixin declarations.", rule.span
|
||||||
).into()),
|
).into()),
|
||||||
AtRule::If(i) => {
|
AtRule::If(i) => {
|
||||||
rules.extend(i.eval(&mut Scope::new(), &Selector::new())?);
|
rules.extend(i.eval(&mut Scope::new(), &Selector::new(), None)?);
|
||||||
}
|
}
|
||||||
AtRule::AtRoot(root_rules) => rules.extend(root_rules),
|
AtRule::AtRoot(root_rules) => rules.extend(root_rules),
|
||||||
AtRule::Unknown(..) => rules.push(rule.map_node(Stmt::AtRule)),
|
AtRule::Unknown(..) => rules.push(rule.map_node(Stmt::AtRule)),
|
||||||
@ -448,7 +449,7 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector)? {
|
while let Some(expr) = eat_expr(&mut self.lexer, scope, super_selector, None)? {
|
||||||
let span = expr.span;
|
let span = expr.span;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
Expr::Style(s) => stmts.push(Spanned {
|
Expr::Style(s) => stmts.push(Spanned {
|
||||||
@ -456,13 +457,13 @@ impl<'a> StyleSheetParser<'a> {
|
|||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
Expr::AtRule(a) => match a {
|
Expr::AtRule(a) => match a {
|
||||||
AtRule::For(f) => stmts.extend(f.ruleset_eval(scope, super_selector)?),
|
AtRule::For(f) => stmts.extend(f.ruleset_eval(scope, super_selector, None)?),
|
||||||
AtRule::While(w) => {
|
AtRule::While(w) => {
|
||||||
stmts.extend(w.ruleset_eval(scope, super_selector, false)?)
|
stmts.extend(w.ruleset_eval(scope, super_selector, false, None)?)
|
||||||
}
|
}
|
||||||
AtRule::Each(e) => stmts.extend(e.ruleset_eval(scope, super_selector)?),
|
AtRule::Each(e) => stmts.extend(e.ruleset_eval(scope, super_selector, None)?),
|
||||||
AtRule::Include(s) => stmts.extend(s),
|
AtRule::Include(s) => stmts.extend(s),
|
||||||
AtRule::If(i) => stmts.extend(i.eval(scope, super_selector)?),
|
AtRule::If(i) => stmts.extend(i.eval(scope, super_selector, None)?),
|
||||||
AtRule::Content => {
|
AtRule::Content => {
|
||||||
return Err((
|
return Err((
|
||||||
"@content is only allowed within mixin declarations.",
|
"@content is only allowed within mixin declarations.",
|
||||||
@ -533,6 +534,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
toks: &mut PeekMoreIterator<I>,
|
toks: &mut PeekMoreIterator<I>,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
super_selector: &Selector,
|
super_selector: &Selector,
|
||||||
|
content: Option<&[Spanned<Stmt>]>,
|
||||||
) -> SassResult<Option<Spanned<Expr>>> {
|
) -> SassResult<Option<Spanned<Expr>>> {
|
||||||
let mut values = Vec::with_capacity(5);
|
let mut values = Vec::with_capacity(5);
|
||||||
let mut span = if let Some(tok) = toks.peek() {
|
let mut span = if let Some(tok) = toks.peek() {
|
||||||
@ -689,6 +691,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
|
|||||||
toks,
|
toks,
|
||||||
scope,
|
scope,
|
||||||
super_selector,
|
super_selector,
|
||||||
|
content,
|
||||||
)?;
|
)?;
|
||||||
return Ok(Some(Spanned {
|
return Ok(Some(Spanned {
|
||||||
node: match rule.node {
|
node: match rule.node {
|
||||||
|
@ -204,3 +204,28 @@ test!(
|
|||||||
"@mixin foo {\n @content;\n}\n\na {\n @include foo {@if true {color: red;}}\n}\n",
|
"@mixin foo {\n @content;\n}\n\na {\n @include foo {@if true {color: red;}}\n}\n",
|
||||||
"a {\n color: red;\n}\n"
|
"a {\n color: red;\n}\n"
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
content_in_control_flow,
|
||||||
|
"@mixin foo() {\n @if true {\n @content;\n }\n}\n\na {\n @include foo {\n color: red;\n }\n}\n",
|
||||||
|
"a {\n color: red;\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
content_inside_unknown_at_rule,
|
||||||
|
"@mixin foo() {\n @foo (max-width: max) {\n @content;\n }\n}\n\na {\n @include foo {\n color: red;\n }\n}\n",
|
||||||
|
"@foo (max-width: max) {\n a {\n color: red;\n }\n}\n"
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
content_inside_media,
|
||||||
|
"@mixin foo() {\n @media (max-width: max) {\n @content;\n }\n}\n\na {\n @include foo {\n color: red;\n }\n}\n",
|
||||||
|
"@media (max-width: max) {\n a {\n color: red;\n }\n}\n"
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
function_inside_mixin,
|
||||||
|
"@mixin foo() {\n @function bar() {\n @return foo;\n }\n}\n\na {\n @include foo {\n color: red;\n }\n}\n",
|
||||||
|
"Error: Mixins may not contain function declarations."
|
||||||
|
);
|
||||||
|
error!(
|
||||||
|
content_inside_control_flow_outside_mixin,
|
||||||
|
"a {\n @if true {\n @content;\n }\n}\n",
|
||||||
|
"Error: @content is only allowed within mixin declarations."
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user