Basic implementation of @charset

This commit is contained in:
ConnorSkees 2020-01-26 15:27:38 -05:00
parent 357647b19c
commit 52c9905b14
4 changed files with 41 additions and 6 deletions

View File

@ -16,6 +16,21 @@ pub(crate) enum AtRule {
Mixin(String, Box<Mixin>), Mixin(String, Box<Mixin>),
Function(String, Box<Function>), Function(String, Box<Function>),
Return(Vec<Token>), Return(Vec<Token>),
// todo: emit only when non-ascii char is found
Charset(Vec<Token>),
}
impl Display for AtRule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AtRule::Charset(toks) => write!(
f,
"@charset {};",
toks.iter().map(|x| x.kind.to_string()).collect::<String>()
),
_ => panic!("attempted to display non-css at rule"),
}
}
} }
impl AtRule { impl AtRule {
@ -73,7 +88,10 @@ impl AtRule {
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 => todo!("@charset not yet implemented"), AtRuleKind::Charset => AtRule::Charset(
toks.take_while(|t| t.kind != TokenKind::Symbol(Symbol::SemiColon))
.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"),

View File

@ -1,4 +1,5 @@
//! # Convert from SCSS AST to CSS //! # Convert from SCSS AST to CSS
use crate::atrule::AtRule;
use crate::{RuleSet, SassResult, Selector, Stmt, Style, StyleSheet}; use crate::{RuleSet, SassResult, Selector, Stmt, Style, StyleSheet};
use std::fmt; use std::fmt;
use std::io::Write; use std::io::Write;
@ -7,14 +8,14 @@ use std::io::Write;
enum Toplevel { enum Toplevel {
RuleSet(Selector, Vec<BlockEntry>), RuleSet(Selector, Vec<BlockEntry>),
MultilineComment(String), MultilineComment(String),
// AtRule(AtRule), AtRule(AtRule),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum BlockEntry { enum BlockEntry {
Style(Style), Style(Style),
MultilineComment(String), MultilineComment(String),
// AtRule(AtRule), AtRule(AtRule),
} }
impl fmt::Display for BlockEntry { impl fmt::Display for BlockEntry {
@ -22,6 +23,7 @@ impl fmt::Display for BlockEntry {
match self { match self {
BlockEntry::Style(s) => writeln!(f, " {}", s), BlockEntry::Style(s) => writeln!(f, " {}", s),
BlockEntry::MultilineComment(s) => writeln!(f, " /*{}*/", s), BlockEntry::MultilineComment(s) => writeln!(f, " /*{}*/", s),
BlockEntry::AtRule(r) => writeln!(f, "{}", r),
} }
} }
} }
@ -77,12 +79,14 @@ 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"),
}; };
} }
vals vals
} }
Stmt::MultilineComment(s) => vec![Toplevel::MultilineComment(s)], Stmt::MultilineComment(s) => vec![Toplevel::MultilineComment(s)],
Stmt::Style(_) => panic!("expected toplevel element, found style"), Stmt::Style(_) => panic!("expected toplevel element, found style"),
Stmt::AtRule(r) => vec![Toplevel::AtRule(r)],
} }
} }
@ -110,6 +114,9 @@ impl Css {
Toplevel::MultilineComment(s) => { Toplevel::MultilineComment(s) => {
writeln!(buf, "/*{}*/", s)?; writeln!(buf, "/*{}*/", s)?;
} }
Toplevel::AtRule(r) => {
writeln!(buf, "{}", r)?;
}
} }
} }
Ok(()) Ok(())

View File

@ -32,6 +32,9 @@ impl<W: Write> PrettyPrinter<W> {
Stmt::Style(s) => { Stmt::Style(s) => {
writeln!(self.buf, "{}{}", padding, s)?; writeln!(self.buf, "{}{}", padding, s)?;
} }
Stmt::AtRule(r) => {
writeln!(self.buf, "{}{}", padding, r)?;
}
} }
Ok(()) Ok(())
} }
@ -69,6 +72,9 @@ impl<W: Write> PrettyPrinter<W> {
Stmt::Style(s) => { Stmt::Style(s) => {
writeln!(self.buf, "{}{}", padding, s)?; writeln!(self.buf, "{}{}", padding, s)?;
} }
Stmt::AtRule(r) => {
writeln!(self.buf, "{}{}", padding, r)?;
}
} }
Ok(()) Ok(())
} }

View File

@ -159,10 +159,10 @@ impl Display for TokenKind {
} }
/// Represents a parsed SASS stylesheet with nesting /// Represents a parsed SASS stylesheet with nesting
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone)]
pub struct StyleSheet(Vec<Stmt>); pub struct StyleSheet(Vec<Stmt>);
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug)]
pub(crate) enum Stmt { pub(crate) enum Stmt {
/// A [`Style`](/grass/style/struct.Style) /// A [`Style`](/grass/style/struct.Style)
Style(Style), Style(Style),
@ -170,6 +170,8 @@ pub(crate) enum Stmt {
RuleSet(RuleSet), RuleSet(RuleSet),
/// A multiline comment: `/* foo bar */` /// A multiline comment: `/* foo bar */`
MultilineComment(String), MultilineComment(String),
/// A CSS rule: `@charset "UTF-8";`
AtRule(AtRule),
} }
/// Represents a single rule set. Rule sets can contain other rule sets /// Represents a single rule set. Rule sets can contain other rule sets
@ -182,7 +184,7 @@ pub(crate) enum Stmt {
/// } /// }
/// } /// }
/// ``` /// ```
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug)]
pub(crate) struct RuleSet { pub(crate) struct RuleSet {
selector: Selector, selector: Selector,
rules: Vec<Stmt>, rules: Vec<Stmt>,
@ -415,6 +417,7 @@ impl<'a> StyleSheetParser<'a> {
AtRule::Function(name, func) => { AtRule::Function(name, func) => {
self.global_scope.functions.insert(name, *func); self.global_scope.functions.insert(name, *func);
} }
AtRule::Charset(toks) => rules.push(Stmt::AtRule(AtRule::Charset(toks))),
AtRule::Error(pos, message) => self.error(pos, &message), AtRule::Error(pos, message) => self.error(pos, &message),
AtRule::Warn(pos, message) => self.warn(pos, &message), AtRule::Warn(pos, message) => self.warn(pos, &message),
AtRule::Debug(pos, message) => self.debug(pos, &message), AtRule::Debug(pos, message) => self.debug(pos, &message),
@ -568,6 +571,7 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
return match AtRule::from_tokens(rule, pos, toks, scope) { return match AtRule::from_tokens(rule, pos, toks, scope) {
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::Debug(a, b) => Ok(Some(Expr::Debug(a, b))), AtRule::Debug(a, b) => Ok(Some(Expr::Debug(a, b))),
AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))), AtRule::Warn(a, b) => Ok(Some(Expr::Warn(a, b))),
AtRule::Error(a, b) => Err((a, b)), AtRule::Error(a, b) => Err((a, b)),