refactor parsing and eval of @ each
This commit is contained in:
parent
092cbe75bb
commit
f60089f4f9
129
src/atrule/each_rule.rs
Normal file
129
src/atrule/each_rule.rs
Normal file
@ -0,0 +1,129 @@
|
||||
use codemap::{Span, Spanned};
|
||||
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
use crate::common::{Brackets, ListSeparator};
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
use crate::selector::Selector;
|
||||
use crate::utils::{
|
||||
devour_whitespace, eat_ident, read_until_closing_curly_brace, read_until_open_curly_brace,
|
||||
};
|
||||
use crate::value::Value;
|
||||
use crate::{Stmt, Token};
|
||||
|
||||
use super::{ruleset_eval, AtRule};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Each {
|
||||
vars: Vec<Spanned<String>>,
|
||||
iter: Vec<Value>,
|
||||
body: Vec<Token>,
|
||||
}
|
||||
|
||||
impl Each {
|
||||
pub fn ruleset_eval(
|
||||
self,
|
||||
scope: &mut Scope,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<Vec<Spanned<Stmt>>> {
|
||||
let mut stmts = Vec::new();
|
||||
for row in self.iter {
|
||||
let this_iterator = match row {
|
||||
Value::List(v, ..) => v,
|
||||
Value::Map(m) => m
|
||||
.into_iter()
|
||||
.map(|(k, v)| Value::List(vec![k, v], ListSeparator::Space, Brackets::None))
|
||||
.collect(),
|
||||
v => vec![v],
|
||||
};
|
||||
|
||||
if self.vars.len() == 1 {
|
||||
scope.insert_var(
|
||||
&self.vars[0],
|
||||
Spanned {
|
||||
node: Value::List(this_iterator, ListSeparator::Space, Brackets::None),
|
||||
span: self.vars[0].span,
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
for (var, val) in self.vars.clone().into_iter().zip(
|
||||
this_iterator
|
||||
.into_iter()
|
||||
.chain(std::iter::once(Value::Null).cycle()),
|
||||
) {
|
||||
scope.insert_var(
|
||||
&var.node,
|
||||
Spanned {
|
||||
node: val,
|
||||
span: var.span,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
ruleset_eval(
|
||||
&mut self.body.clone().into_iter().peekmore(),
|
||||
scope,
|
||||
super_selector,
|
||||
false,
|
||||
&mut stmts,
|
||||
)?;
|
||||
}
|
||||
Ok(stmts)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_each<I: Iterator<Item = Token>>(
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: &mut Scope,
|
||||
super_selector: &Selector,
|
||||
mut span: Span,
|
||||
) -> SassResult<AtRule> {
|
||||
devour_whitespace(toks);
|
||||
let mut vars = Vec::new();
|
||||
loop {
|
||||
let next = toks.next().ok_or(("expected \"$\".", span))?;
|
||||
span = next.pos();
|
||||
match next.kind {
|
||||
'$' => vars.push(eat_ident(toks, scope, super_selector)?),
|
||||
_ => return Err(("expected \"$\".", next.pos()).into()),
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
if toks
|
||||
.peek()
|
||||
.ok_or(("expected \"$\".", vars[vars.len() - 1].span))?
|
||||
.kind
|
||||
== ','
|
||||
{
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if toks.peek().is_none() {
|
||||
todo!()
|
||||
}
|
||||
let i = eat_ident(toks, scope, super_selector)?;
|
||||
if i.node.to_ascii_lowercase() != "in" {
|
||||
return Err(("Expected \"in\".", i.span).into());
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
let iter_val = Value::from_vec(read_until_open_curly_brace(toks), scope, super_selector)?;
|
||||
let iter = match iter_val.node.eval(iter_val.span)?.node {
|
||||
Value::List(v, ..) => v,
|
||||
Value::Map(m) => m
|
||||
.into_iter()
|
||||
.map(|(k, v)| Value::List(vec![k, v], ListSeparator::Space, Brackets::None))
|
||||
.collect(),
|
||||
v => vec![v],
|
||||
};
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
let mut body = read_until_closing_curly_brace(toks);
|
||||
body.push(toks.next().unwrap());
|
||||
devour_whitespace(toks);
|
||||
|
||||
Ok(AtRule::Each(Each { vars, iter, body }))
|
||||
}
|
@ -6,7 +6,7 @@ use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
use num_traits::cast::ToPrimitive;
|
||||
|
||||
use super::parse::eat_stmts;
|
||||
use super::parse::ruleset_eval;
|
||||
use super::AtRule;
|
||||
|
||||
use crate::error::SassResult;
|
||||
@ -42,27 +42,13 @@ impl For {
|
||||
span: self.var.span,
|
||||
},
|
||||
)?;
|
||||
for stmt in eat_stmts(
|
||||
ruleset_eval(
|
||||
&mut self.body.clone().into_iter().peekmore(),
|
||||
scope,
|
||||
super_selector,
|
||||
false,
|
||||
)? {
|
||||
match stmt.node {
|
||||
Stmt::AtRule(AtRule::For(f)) => {
|
||||
stmts.extend(f.ruleset_eval(scope, super_selector)?)
|
||||
}
|
||||
Stmt::AtRule(AtRule::While(w)) => {
|
||||
// TODO: should at_root be false? scoping
|
||||
stmts.extend(w.ruleset_eval(scope, super_selector, false)?)
|
||||
}
|
||||
Stmt::AtRule(AtRule::Include(s)) | Stmt::AtRule(AtRule::Each(s)) => {
|
||||
stmts.extend(s)
|
||||
}
|
||||
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
||||
_ => stmts.push(stmt),
|
||||
}
|
||||
}
|
||||
&mut stmts,
|
||||
)?;
|
||||
}
|
||||
Ok(stmts)
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ impl Function {
|
||||
val = Value::from_vec(w.cond.clone(), scope, super_selector)?;
|
||||
}
|
||||
}
|
||||
Stmt::AtRule(AtRule::Each(..)) => todo!("@each in @function"),
|
||||
_ => return Err(("This at-rule is not allowed here.", stmt.span).into()),
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use codemap::Spanned;
|
||||
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
use super::{eat_stmts, AtRule};
|
||||
use super::ruleset_eval;
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
@ -120,18 +120,13 @@ impl If {
|
||||
if !found_true {
|
||||
toks = self.else_;
|
||||
}
|
||||
for stmt in eat_stmts(
|
||||
ruleset_eval(
|
||||
&mut toks.into_iter().peekmore(),
|
||||
scope,
|
||||
super_selector,
|
||||
false,
|
||||
)? {
|
||||
match stmt.node {
|
||||
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
||||
Stmt::RuleSet(r) if r.selector.is_empty() => stmts.extend(r.rules),
|
||||
_ => stmts.push(stmt),
|
||||
}
|
||||
}
|
||||
&mut stmts,
|
||||
)?;
|
||||
Ok(stmts)
|
||||
}
|
||||
}
|
||||
|
@ -126,10 +126,13 @@ impl Mixin {
|
||||
AtRule::For(f) => {
|
||||
stmts.extend(f.ruleset_eval(&mut self.scope, super_selector)?)
|
||||
}
|
||||
AtRule::Each(e) => {
|
||||
stmts.extend(e.ruleset_eval(&mut self.scope, super_selector)?)
|
||||
}
|
||||
AtRule::While(w) => {
|
||||
stmts.extend(w.ruleset_eval(&mut self.scope, super_selector, false)?)
|
||||
}
|
||||
AtRule::Include(s) | AtRule::Each(s) => stmts.extend(s),
|
||||
AtRule::Include(s) => stmts.extend(s),
|
||||
AtRule::If(i) => stmts.extend(i.eval(&mut self.scope.clone(), super_selector)?),
|
||||
AtRule::Content => stmts.extend(self.content.clone()),
|
||||
AtRule::Return(..) => {
|
||||
|
@ -2,26 +2,27 @@ use codemap::{Span, Spanned};
|
||||
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
use crate::common::{Brackets, ListSeparator};
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
use crate::selector::Selector;
|
||||
use crate::utils::{
|
||||
devour_whitespace, eat_ident, read_until_closing_curly_brace, read_until_open_curly_brace,
|
||||
devour_whitespace, read_until_closing_curly_brace, read_until_open_curly_brace,
|
||||
read_until_semicolon_or_closing_curly_brace,
|
||||
};
|
||||
use crate::value::Value;
|
||||
use crate::{RuleSet, Stmt, Token};
|
||||
|
||||
use each_rule::{parse_each, Each};
|
||||
use for_rule::For;
|
||||
pub(crate) use function::Function;
|
||||
pub(crate) use if_rule::If;
|
||||
pub(crate) use kind::AtRuleKind;
|
||||
pub(crate) use mixin::{eat_include, Mixin};
|
||||
use parse::{eat_stmts, eat_stmts_at_root};
|
||||
use parse::{eat_stmts, eat_stmts_at_root, ruleset_eval};
|
||||
use unknown::UnknownAtRule;
|
||||
use while_rule::{parse_while, While};
|
||||
|
||||
mod each_rule;
|
||||
mod for_rule;
|
||||
mod function;
|
||||
mod if_rule;
|
||||
@ -33,8 +34,8 @@ mod while_rule;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum AtRule {
|
||||
Warn(String),
|
||||
Debug(String),
|
||||
Warn(Spanned<String>),
|
||||
Debug(Spanned<String>),
|
||||
Mixin(String, Box<Mixin>),
|
||||
Function(String, Box<Function>),
|
||||
Return(Vec<Token>),
|
||||
@ -42,7 +43,7 @@ pub(crate) enum AtRule {
|
||||
Content,
|
||||
Unknown(UnknownAtRule),
|
||||
For(For),
|
||||
Each(Vec<Spanned<Stmt>>),
|
||||
Each(Each),
|
||||
While(While),
|
||||
Include(Vec<Spanned<Stmt>>),
|
||||
If(If),
|
||||
@ -86,7 +87,10 @@ impl AtRule {
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
Spanned {
|
||||
node: AtRule::Warn(message.to_css_string(span)?),
|
||||
node: AtRule::Warn(Spanned {
|
||||
node: message.to_css_string(span)?,
|
||||
span,
|
||||
}),
|
||||
span,
|
||||
}
|
||||
}
|
||||
@ -105,7 +109,10 @@ impl AtRule {
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
Spanned {
|
||||
node: AtRule::Debug(message.inspect(span)?),
|
||||
node: AtRule::Debug(Spanned {
|
||||
node: message.inspect(span)?,
|
||||
span,
|
||||
}),
|
||||
span,
|
||||
}
|
||||
}
|
||||
@ -199,101 +206,10 @@ impl AtRule {
|
||||
span: kind_span,
|
||||
}
|
||||
}
|
||||
AtRuleKind::Each => {
|
||||
let mut stmts = Vec::new();
|
||||
devour_whitespace(toks);
|
||||
let mut vars = Vec::new();
|
||||
let mut span = kind_span;
|
||||
loop {
|
||||
let next = toks.next().ok_or(("expected \"$\".", span))?;
|
||||
span = next.pos();
|
||||
match next.kind {
|
||||
'$' => vars.push(eat_ident(toks, scope, super_selector)?),
|
||||
_ => return Err(("expected \"$\".", next.pos()).into()),
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
if toks
|
||||
.peek()
|
||||
.ok_or(("expected \"$\".", vars[vars.len() - 1].span))?
|
||||
.kind
|
||||
== ','
|
||||
{
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if toks.peek().is_none() {
|
||||
todo!()
|
||||
}
|
||||
let i = eat_ident(toks, scope, super_selector)?;
|
||||
if i.node.to_ascii_lowercase() != "in" {
|
||||
return Err(("Expected \"in\".", i.span).into());
|
||||
}
|
||||
devour_whitespace(toks);
|
||||
let iter_val =
|
||||
Value::from_vec(read_until_open_curly_brace(toks), scope, super_selector)?;
|
||||
let iterator = match iter_val.node.eval(iter_val.span)?.node {
|
||||
Value::List(v, ..) => v,
|
||||
Value::Map(m) => m
|
||||
.into_iter()
|
||||
.map(|(k, v)| Value::List(vec![k, v], ListSeparator::Space, Brackets::None))
|
||||
.collect(),
|
||||
v => vec![v],
|
||||
};
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
let mut body = read_until_closing_curly_brace(toks);
|
||||
body.push(toks.next().unwrap());
|
||||
devour_whitespace(toks);
|
||||
|
||||
for row in iterator {
|
||||
let this_iterator = match row {
|
||||
Value::List(v, ..) => v,
|
||||
Value::Map(m) => m
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
Value::List(vec![k, v], ListSeparator::Space, Brackets::None)
|
||||
})
|
||||
.collect(),
|
||||
v => vec![v],
|
||||
};
|
||||
|
||||
if vars.len() == 1 {
|
||||
scope.insert_var(
|
||||
&vars[0],
|
||||
Spanned {
|
||||
node: Value::List(
|
||||
this_iterator,
|
||||
ListSeparator::Space,
|
||||
Brackets::None,
|
||||
),
|
||||
span: vars[0].span,
|
||||
},
|
||||
)?;
|
||||
} else {
|
||||
for (var, val) in vars.clone().into_iter().zip(
|
||||
this_iterator
|
||||
.into_iter()
|
||||
.chain(std::iter::once(Value::Null).cycle()),
|
||||
) {
|
||||
scope.insert_var(&var, Spanned { node: val, span })?;
|
||||
}
|
||||
}
|
||||
|
||||
stmts.extend(eat_stmts(
|
||||
&mut body.clone().into_iter().peekmore(),
|
||||
scope,
|
||||
super_selector,
|
||||
false,
|
||||
)?);
|
||||
}
|
||||
Spanned {
|
||||
node: AtRule::Each(stmts),
|
||||
AtRuleKind::Each => Spanned {
|
||||
node: parse_each(toks, scope, super_selector, kind_span)?,
|
||||
span: kind_span,
|
||||
}
|
||||
}
|
||||
},
|
||||
AtRuleKind::Extend => todo!("@extend not yet implemented"),
|
||||
AtRuleKind::If => Spanned {
|
||||
node: AtRule::If(If::from_tokens(toks)?),
|
||||
|
@ -2,6 +2,8 @@ use codemap::Spanned;
|
||||
|
||||
use peekmore::PeekMoreIterator;
|
||||
|
||||
use super::AtRule;
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::{global_var_exists, insert_global_var, Scope};
|
||||
use crate::selector::Selector;
|
||||
@ -100,3 +102,26 @@ pub(crate) fn eat_stmts_at_root<I: Iterator<Item = Token>>(
|
||||
}
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
pub(crate) fn ruleset_eval<I: Iterator<Item = Token>>(
|
||||
toks: &mut PeekMoreIterator<I>,
|
||||
scope: &mut Scope,
|
||||
super_selector: &Selector,
|
||||
at_root: bool,
|
||||
stmts: &mut Vec<Spanned<Stmt>>,
|
||||
) -> SassResult<()> {
|
||||
for stmt in eat_stmts(toks, scope, super_selector, at_root)? {
|
||||
match stmt.node {
|
||||
Stmt::AtRule(AtRule::For(f)) => stmts.extend(f.ruleset_eval(scope, super_selector)?),
|
||||
Stmt::AtRule(AtRule::Each(e)) => stmts.extend(e.ruleset_eval(scope, super_selector)?),
|
||||
Stmt::AtRule(AtRule::While(w)) => {
|
||||
// TODO: should at_root be false? scoping
|
||||
stmts.extend(w.ruleset_eval(scope, super_selector, at_root)?)
|
||||
}
|
||||
Stmt::AtRule(AtRule::Include(s)) => stmts.extend(s),
|
||||
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
||||
_ => stmts.push(stmt),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use codemap::{Span, Spanned};
|
||||
|
||||
use peekmore::{PeekMore, PeekMoreIterator};
|
||||
|
||||
use super::{eat_stmts, AtRule};
|
||||
use super::{ruleset_eval, AtRule};
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
@ -30,26 +30,13 @@ impl While {
|
||||
let mut val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
||||
let scope = &mut scope.clone();
|
||||
while val.node.is_true(val.span)? {
|
||||
for stmt in eat_stmts(
|
||||
ruleset_eval(
|
||||
&mut self.body.clone().into_iter().peekmore(),
|
||||
scope,
|
||||
super_selector,
|
||||
at_root,
|
||||
)? {
|
||||
match stmt.node {
|
||||
Stmt::AtRule(AtRule::For(f)) => {
|
||||
stmts.extend(f.ruleset_eval(scope, super_selector)?)
|
||||
}
|
||||
Stmt::AtRule(AtRule::While(w)) => {
|
||||
stmts.extend(w.ruleset_eval(scope, super_selector, at_root)?)
|
||||
}
|
||||
Stmt::AtRule(AtRule::Include(s)) | Stmt::AtRule(AtRule::Each(s)) => {
|
||||
stmts.extend(s)
|
||||
}
|
||||
Stmt::AtRule(AtRule::If(i)) => stmts.extend(i.eval(scope, super_selector)?),
|
||||
_ => stmts.push(stmt),
|
||||
}
|
||||
}
|
||||
&mut stmts,
|
||||
)?;
|
||||
val = Value::from_vec(self.cond.clone(), scope, super_selector)?;
|
||||
}
|
||||
Ok(stmts)
|
||||
|
@ -16,7 +16,7 @@ impl SassError {
|
||||
pub(crate) fn raw(self) -> (String, Span) {
|
||||
match self.kind {
|
||||
SassErrorKind::Raw(string, span) => (string, span),
|
||||
_ => todo!(),
|
||||
e => todo!("unable to get raw of {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,17 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
use codemap::Spanned;
|
||||
use codemap::{CodeMap, Spanned};
|
||||
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
use crate::{Stmt, StyleSheet};
|
||||
|
||||
pub(crate) fn import(ctx: &Path, path: &Path) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
|
||||
pub(crate) fn import(
|
||||
ctx: &Path,
|
||||
path: &Path,
|
||||
map: &mut CodeMap,
|
||||
) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
|
||||
let mut rules = Vec::new();
|
||||
let mut scope = Scope::new();
|
||||
if path.is_absolute() {
|
||||
@ -39,7 +43,7 @@ pub(crate) fn import(ctx: &Path, path: &Path) -> SassResult<(Vec<Spanned<Stmt>>,
|
||||
for name in &paths {
|
||||
if name.is_file() {
|
||||
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"), map)?;
|
||||
rules.extend(rules2);
|
||||
scope.extend(scope2);
|
||||
}
|
||||
|
25
src/lib.rs
25
src/lib.rs
@ -237,7 +237,7 @@ impl StyleSheet {
|
||||
StyleSheetParser {
|
||||
lexer: Lexer::new(&file).peekmore(),
|
||||
nesting: 0,
|
||||
map: &map,
|
||||
map: &mut map,
|
||||
path: Path::new(""),
|
||||
}
|
||||
.parse_toplevel()
|
||||
@ -245,7 +245,7 @@ impl StyleSheet {
|
||||
.0,
|
||||
))
|
||||
.map_err(|e| raw_to_parse_error(&map, e))?
|
||||
.pretty_print()
|
||||
.pretty_print(&map)
|
||||
.map_err(|e| raw_to_parse_error(&map, e))
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ impl StyleSheet {
|
||||
StyleSheetParser {
|
||||
lexer: Lexer::new(&file).peekmore(),
|
||||
nesting: 0,
|
||||
map: &map,
|
||||
map: &mut map,
|
||||
path: p.as_ref(),
|
||||
}
|
||||
.parse_toplevel()
|
||||
@ -276,19 +276,19 @@ impl StyleSheet {
|
||||
.0,
|
||||
))
|
||||
.map_err(|e| raw_to_parse_error(&map, e))?
|
||||
.pretty_print()
|
||||
.pretty_print(&map)
|
||||
.map_err(|e| raw_to_parse_error(&map, e))
|
||||
}
|
||||
|
||||
pub(crate) fn export_from_path<P: AsRef<Path> + Into<String> + Clone>(
|
||||
p: &P,
|
||||
map: &mut CodeMap,
|
||||
) -> SassResult<(Vec<Spanned<Stmt>>, Scope)> {
|
||||
let mut map = CodeMap::new();
|
||||
let file = map.add_file(p.clone().into(), String::from_utf8(fs::read(p)?)?);
|
||||
Ok(StyleSheetParser {
|
||||
lexer: Lexer::new(&file).peekmore(),
|
||||
nesting: 0,
|
||||
map: &map,
|
||||
map,
|
||||
path: p.as_ref(),
|
||||
}
|
||||
.parse_toplevel()?)
|
||||
@ -302,7 +302,7 @@ impl StyleSheet {
|
||||
struct StyleSheetParser<'a> {
|
||||
lexer: PeekMoreIterator<Lexer<'a>>,
|
||||
nesting: u32,
|
||||
map: &'a CodeMap,
|
||||
map: &'a mut CodeMap,
|
||||
path: &'a Path,
|
||||
}
|
||||
|
||||
@ -387,7 +387,7 @@ impl<'a> StyleSheetParser<'a> {
|
||||
|
||||
devour_whitespace(&mut self.lexer);
|
||||
|
||||
let (new_rules, new_scope) = import(self.path, file_name.as_ref())?;
|
||||
let (new_rules, new_scope) = import(self.path, file_name.as_ref(), &mut self.map)?;
|
||||
rules.extend(new_rules);
|
||||
GLOBAL_SCOPE.with(|s| {
|
||||
s.borrow_mut().extend(new_scope);
|
||||
@ -412,8 +412,10 @@ impl<'a> StyleSheetParser<'a> {
|
||||
}
|
||||
AtRule::For(f) => rules.extend(f.ruleset_eval(&mut Scope::new(), &Selector::new())?),
|
||||
AtRule::While(w) => rules.extend(w.ruleset_eval(&mut Scope::new(), &Selector::new(), true)?),
|
||||
AtRule::Include(s)
|
||||
| AtRule::Each(s) => rules.extend(s),
|
||||
AtRule::Each(e) => {
|
||||
rules.extend(e.ruleset_eval(&mut Scope::new(), &Selector::new())?)
|
||||
}
|
||||
AtRule::Include(s) => rules.extend(s),
|
||||
AtRule::Content => return Err(
|
||||
("@content is only allowed within mixin declarations.", rule.span
|
||||
).into()),
|
||||
@ -461,7 +463,8 @@ impl<'a> StyleSheetParser<'a> {
|
||||
AtRule::While(w) => {
|
||||
stmts.extend(w.ruleset_eval(scope, super_selector, false)?)
|
||||
}
|
||||
AtRule::Include(s) | AtRule::Each(s) => stmts.extend(s),
|
||||
AtRule::Each(e) => stmts.extend(e.ruleset_eval(scope, super_selector)?),
|
||||
AtRule::Include(s) => stmts.extend(s),
|
||||
AtRule::If(i) => stmts.extend(i.eval(scope, super_selector)?),
|
||||
AtRule::Content => {
|
||||
return Err((
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! # Convert from SCSS AST to CSS
|
||||
use std::io::Write;
|
||||
|
||||
use codemap::{CodeMap, Span};
|
||||
|
||||
use crate::atrule::AtRule;
|
||||
use crate::error::SassResult;
|
||||
use crate::{RuleSet, Selector, Stmt, Style, StyleSheet};
|
||||
@ -123,9 +125,9 @@ impl Css {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn pretty_print(self) -> SassResult<String> {
|
||||
pub fn pretty_print(self, map: &CodeMap) -> SassResult<String> {
|
||||
let mut string = Vec::new();
|
||||
self._inner_pretty_print(&mut string, 0)?;
|
||||
self._inner_pretty_print(&mut string, map, 0)?;
|
||||
if string.iter().any(|s| !s.is_ascii()) {
|
||||
return Ok(format!(
|
||||
"@charset \"UTF-8\";\n{}",
|
||||
@ -135,7 +137,33 @@ impl Css {
|
||||
Ok(String::from_utf8(string)?)
|
||||
}
|
||||
|
||||
fn _inner_pretty_print(self, buf: &mut Vec<u8>, nesting: usize) -> SassResult<()> {
|
||||
fn debug(map: &CodeMap, span: Span, message: &str) {
|
||||
let loc = map.look_up_span(span);
|
||||
eprintln!(
|
||||
"{}:{} Debug: {}",
|
||||
loc.file.name(),
|
||||
loc.begin.line + 1,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
fn warn(map: &CodeMap, span: Span, message: &str) {
|
||||
let loc = map.look_up_span(span);
|
||||
eprintln!(
|
||||
"Warning: {}\n {} {}:{} root stylesheet",
|
||||
message,
|
||||
loc.file.name(),
|
||||
loc.begin.line + 1,
|
||||
loc.begin.column + 1
|
||||
);
|
||||
}
|
||||
|
||||
fn _inner_pretty_print(
|
||||
self,
|
||||
buf: &mut Vec<u8>,
|
||||
map: &CodeMap,
|
||||
nesting: usize,
|
||||
) -> SassResult<()> {
|
||||
let mut has_written = false;
|
||||
let padding = vec![' '; nesting * 2].iter().collect::<String>();
|
||||
for block in self.blocks {
|
||||
@ -155,7 +183,8 @@ impl Css {
|
||||
has_written = true;
|
||||
writeln!(buf, "{}/*{}*/", padding, s)?;
|
||||
}
|
||||
Toplevel::AtRule(r) => match r {
|
||||
Toplevel::AtRule(r) => {
|
||||
match r {
|
||||
AtRule::Unknown(u) => {
|
||||
if u.body.is_empty() {
|
||||
continue;
|
||||
@ -166,11 +195,14 @@ impl Css {
|
||||
writeln!(buf, "{}@{} {} {{", padding, u.name, u.params)?;
|
||||
}
|
||||
Css::from_stylesheet(StyleSheet::from_stmts(u.body))?
|
||||
._inner_pretty_print(buf, nesting + 1)?;
|
||||
._inner_pretty_print(buf, map, nesting + 1)?;
|
||||
writeln!(buf, "{}}}", padding)?;
|
||||
}
|
||||
AtRule::Debug(e) => Self::debug(map, e.span, &e.node),
|
||||
AtRule::Warn(e) => Self::warn(map, e.span, &e.node),
|
||||
_ => todo!("at-rule other than unknown at toplevel: {:?}", r),
|
||||
},
|
||||
}
|
||||
}
|
||||
Toplevel::Style(s) => {
|
||||
writeln!(buf, "{}{}", padding, s.to_string()?)?;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user