Parse and construct unknown at rules

This commit is contained in:
ConnorSkees 2020-02-22 11:58:30 -05:00
parent cacf8c41ab
commit d114509464

View File

@ -5,8 +5,10 @@ use crate::common::{Pos, Scope, Symbol};
use crate::error::SassResult; use crate::error::SassResult;
use crate::function::Function; use crate::function::Function;
use crate::mixin::Mixin; use crate::mixin::Mixin;
use crate::utils::devour_whitespace; use crate::selector::Selector;
use crate::{Token, TokenKind}; use crate::utils::{devour_whitespace, parse_interpolation};
use crate::{eat_expr, Expr, Stmt};
use crate::{RuleSet, Token, TokenKind};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum AtRule { pub(crate) enum AtRule {
@ -18,19 +20,15 @@ pub(crate) enum AtRule {
Return(Vec<Token>), Return(Vec<Token>),
// todo: emit only when non-ascii char is found // todo: emit only when non-ascii char is found
Charset(Vec<Token>), Charset(Vec<Token>),
Unknown(UnknownAtRule),
} }
impl Display for AtRule { #[derive(Debug, Clone)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { pub(crate) struct UnknownAtRule {
match self { pub name: String,
AtRule::Charset(toks) => write!( pub super_selector: Selector,
f, pub params: String,
"@charset {};", pub body: Vec<Stmt>,
toks.iter().map(|x| x.kind.to_string()).collect::<String>()
),
_ => panic!("attempted to display non-css at rule"),
}
}
} }
impl AtRule { impl AtRule {
@ -41,13 +39,13 @@ impl AtRule {
scope: &Scope, scope: &Scope,
) -> SassResult<AtRule> { ) -> SassResult<AtRule> {
devour_whitespace(toks); devour_whitespace(toks);
match rule { Ok(match rule {
AtRuleKind::Error => { AtRuleKind::Error => {
let message = toks let message = toks
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon)) .take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string()) .map(|x| x.kind.to_string())
.collect::<String>(); .collect::<String>();
Ok(AtRule::Error(pos, message)) AtRule::Error(pos, message)
} }
AtRuleKind::Warn => { AtRuleKind::Warn => {
let message = toks let message = toks
@ -55,7 +53,7 @@ impl AtRule {
.map(|x| x.kind.to_string()) .map(|x| x.kind.to_string())
.collect::<String>(); .collect::<String>();
devour_whitespace(toks); devour_whitespace(toks);
Ok(AtRule::Warn(pos, message)) AtRule::Warn(pos, message)
} }
AtRuleKind::Debug => { AtRuleKind::Debug => {
let message = toks let message = toks
@ -64,44 +62,102 @@ impl AtRule {
.map(|x| x.kind.to_string()) .map(|x| x.kind.to_string())
.collect::<String>(); .collect::<String>();
devour_whitespace(toks); devour_whitespace(toks);
Ok(AtRule::Debug(pos, message)) AtRule::Debug(pos, message)
} }
AtRuleKind::Mixin => { AtRuleKind::Mixin => {
let (name, mixin) = Mixin::decl_from_tokens(toks, scope)?; let (name, mixin) = Mixin::decl_from_tokens(toks, scope)?;
Ok(AtRule::Mixin(name, Box::new(mixin))) AtRule::Mixin(name, Box::new(mixin))
} }
AtRuleKind::Function => { AtRuleKind::Function => {
let (name, func) = Function::decl_from_tokens(toks, scope)?; let (name, func) = Function::decl_from_tokens(toks, scope)?;
Ok(AtRule::Function(name, Box::new(func))) AtRule::Function(name, Box::new(func))
} }
AtRuleKind::Return => Ok(AtRule::Return( AtRuleKind::Return => AtRule::Return(
// todo: return may not end in semicolon // todo: return may not end in semicolon
toks.take_while(|t| t.kind != TokenKind::Symbol(Symbol::SemiColon)) toks.take_while(|t| t.kind != TokenKind::Symbol(Symbol::SemiColon))
.collect(), .collect(),
)), ),
AtRuleKind::Use => todo!("@use not yet implemented"), AtRuleKind::Use => todo!("@use not yet implemented"),
AtRuleKind::Annotation => todo!("@annotation not yet implemented"), AtRuleKind::Annotation => todo!("@annotation not yet implemented"),
AtRuleKind::AtRoot => todo!("@at-root not yet implemented"), AtRuleKind::AtRoot => todo!("@at-root not yet implemented"),
AtRuleKind::Charset => Ok(AtRule::Charset( AtRuleKind::Charset => AtRule::Charset(
toks.take_while(|t| t.kind != TokenKind::Symbol(Symbol::SemiColon)) toks.take_while(|t| t.kind != TokenKind::Symbol(Symbol::SemiColon))
.collect(), .collect(),
)), ),
AtRuleKind::Each => todo!("@each not yet implemented"), AtRuleKind::Each => todo!("@each not yet implemented"),
AtRuleKind::Extend => todo!("@extend not yet implemented"), AtRuleKind::Extend => todo!("@extend not yet implemented"),
AtRuleKind::If => todo!("@if not yet implemented"), AtRuleKind::If => todo!("@if not yet implemented"),
AtRuleKind::Else => todo!("@else not yet implemented"), AtRuleKind::Else => todo!("@else not yet implemented"),
AtRuleKind::For => todo!("@for not yet implemented"), AtRuleKind::For => todo!("@for not yet implemented"),
AtRuleKind::While => todo!("@while not yet implemented"), AtRuleKind::While => todo!("@while not yet implemented"),
AtRuleKind::Media => todo!("@media not yet implemented"),
AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"), AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"),
AtRuleKind::Unknown(_) => todo!("unknown @ rules are not yet implemented"), AtRuleKind::Unknown(name) => {
_ => todo!("encountered unimplemented at rule"), let mut params = String::new();
while let Some(tok) = toks.next() {
match tok.kind {
TokenKind::Symbol(Symbol::OpenCurlyBrace) => break,
TokenKind::Interpolation => {
params.push_str(
&parse_interpolation(toks, scope)?
.into_iter()
.map(|x| x.kind.to_string())
.collect::<String>(),
);
continue;
} }
TokenKind::Variable(..) => params.push('$'),
_ => {}
}
params.push_str(&tok.kind.to_string());
}
let body = eat_unknown_atrule_body(toks, scope, &Selector::new())?;
let u = UnknownAtRule {
name: name.clone(),
super_selector: Selector::new(),
params,
body,
};
AtRule::Unknown(u)
}
_ => todo!("encountered unimplemented at rule"),
})
} }
} }
#[allow(dead_code, unused_variables)] fn eat_unknown_atrule_body<I: Iterator<Item = Token>>(
fn eat_media_query<I: Iterator<Item = Token>>(toks: &mut Peekable<I>) {} toks: &mut Peekable<I>,
scope: &Scope,
super_selector: &Selector,
) -> SassResult<Vec<Stmt>> {
let mut stmts = Vec::new();
while let Some(expr) = eat_expr(toks, scope, super_selector)? {
match expr {
Expr::Style(s) => stmts.push(Stmt::Style(s)),
Expr::Styles(s) => stmts.extend(s.into_iter().map(Stmt::Style)),
Expr::Include(s) => stmts.extend(s),
Expr::MixinDecl(..) | Expr::FunctionDecl(..) | Expr::Debug(..) | Expr::Warn(..) => {
todo!()
}
Expr::Selector(selector) => {
let rules = eat_unknown_atrule_body(toks, scope, &super_selector.zip(&selector))?;
stmts.push(Stmt::RuleSet(RuleSet {
super_selector: super_selector.clone(),
selector,
rules,
}));
}
Expr::VariableDecl(..) => {
todo!()
// self.scope.insert_var(&name, *val);
}
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
}
}
Ok(stmts)
}
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum AtRuleKind { pub enum AtRuleKind {
@ -144,10 +200,6 @@ pub enum AtRuleKind {
/// Tells the CSS engine that all its content must be considered /// Tells the CSS engine that all its content must be considered
/// prefixed with an XML namespace /// prefixed with an XML namespace
Namespace, Namespace,
/// A conditional group rule that will apply its content if
/// the device meets the criteria of the
/// condition defined using a media query
Media,
/// A conditional group rule that will apply its content if the /// A conditional group rule that will apply its content if the
/// browser meets the criteria of the given condition /// browser meets the criteria of the given condition
Supports, Supports,
@ -184,7 +236,7 @@ pub enum AtRuleKind {
CounterStyle, CounterStyle,
/// An unknown at rule. /// An unknown at rule.
/// For compatibility, they are parsed the same as @media /// For forward compatibility, they are parsed the same as @media
Unknown(String), Unknown(String),
} }
@ -210,7 +262,6 @@ impl From<&str> for AtRuleKind {
"while" => Self::While, "while" => Self::While,
"charset" => Self::Charset, "charset" => Self::Charset,
"namespace" => Self::Namespace, "namespace" => Self::Namespace,
"media" => Self::Media,
"supports" => Self::Supports, "supports" => Self::Supports,
"page" => Self::Page, "page" => Self::Page,
"fontface" => Self::FontFace, "fontface" => Self::FontFace,
@ -252,7 +303,6 @@ impl Display for AtRuleKind {
Self::While => write!(f, "@while"), Self::While => write!(f, "@while"),
Self::Charset => write!(f, "@charset"), Self::Charset => write!(f, "@charset"),
Self::Namespace => write!(f, "@namespace"), Self::Namespace => write!(f, "@namespace"),
Self::Media => write!(f, "@media"),
Self::Supports => write!(f, "@supports"), Self::Supports => write!(f, "@supports"),
Self::Page => write!(f, "@page"), Self::Page => write!(f, "@page"),
Self::FontFace => write!(f, "@fontface"), Self::FontFace => write!(f, "@fontface"),