From 52c9905b145657fd234121512a9f3fa0c5a27315 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sun, 26 Jan 2020 15:27:38 -0500 Subject: [PATCH] Basic implementation of @charset --- src/atrule.rs | 20 +++++++++++++++++++- src/css.rs | 11 +++++++++-- src/format.rs | 6 ++++++ src/lib.rs | 10 +++++++--- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/atrule.rs b/src/atrule.rs index a0703a2..c7284fb 100644 --- a/src/atrule.rs +++ b/src/atrule.rs @@ -16,6 +16,21 @@ pub(crate) enum AtRule { Mixin(String, Box), Function(String, Box), Return(Vec), + // todo: emit only when non-ascii char is found + Charset(Vec), +} + +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::() + ), + _ => panic!("attempted to display non-css at rule"), + } + } } impl AtRule { @@ -73,7 +88,10 @@ impl AtRule { AtRuleKind::Use => todo!("@use not yet implemented"), AtRuleKind::Annotation => todo!("@annotation 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::Extend => todo!("@extend not yet implemented"), AtRuleKind::If => todo!("@if not yet implemented"), diff --git a/src/css.rs b/src/css.rs index d520a1f..ebb3661 100644 --- a/src/css.rs +++ b/src/css.rs @@ -1,4 +1,5 @@ //! # Convert from SCSS AST to CSS +use crate::atrule::AtRule; use crate::{RuleSet, SassResult, Selector, Stmt, Style, StyleSheet}; use std::fmt; use std::io::Write; @@ -7,14 +8,14 @@ use std::io::Write; enum Toplevel { RuleSet(Selector, Vec), MultilineComment(String), - // AtRule(AtRule), + AtRule(AtRule), } #[derive(Debug, Clone)] enum BlockEntry { Style(Style), MultilineComment(String), - // AtRule(AtRule), + AtRule(AtRule), } impl fmt::Display for BlockEntry { @@ -22,6 +23,7 @@ impl fmt::Display for BlockEntry { match self { BlockEntry::Style(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) .expect("expected block to exist") .push_comment(s), + Stmt::AtRule(_) => todo!("at rule inside css block"), }; } vals } Stmt::MultilineComment(s) => vec![Toplevel::MultilineComment(s)], Stmt::Style(_) => panic!("expected toplevel element, found style"), + Stmt::AtRule(r) => vec![Toplevel::AtRule(r)], } } @@ -110,6 +114,9 @@ impl Css { Toplevel::MultilineComment(s) => { writeln!(buf, "/*{}*/", s)?; } + Toplevel::AtRule(r) => { + writeln!(buf, "{}", r)?; + } } } Ok(()) diff --git a/src/format.rs b/src/format.rs index 1e6b420..a3e3b6a 100644 --- a/src/format.rs +++ b/src/format.rs @@ -32,6 +32,9 @@ impl PrettyPrinter { Stmt::Style(s) => { writeln!(self.buf, "{}{}", padding, s)?; } + Stmt::AtRule(r) => { + writeln!(self.buf, "{}{}", padding, r)?; + } } Ok(()) } @@ -69,6 +72,9 @@ impl PrettyPrinter { Stmt::Style(s) => { writeln!(self.buf, "{}{}", padding, s)?; } + Stmt::AtRule(r) => { + writeln!(self.buf, "{}{}", padding, r)?; + } } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 08ee9aa..a662857 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,10 +159,10 @@ impl Display for TokenKind { } /// Represents a parsed SASS stylesheet with nesting -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone)] pub struct StyleSheet(Vec); -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug)] pub(crate) enum Stmt { /// A [`Style`](/grass/style/struct.Style) Style(Style), @@ -170,6 +170,8 @@ pub(crate) enum Stmt { RuleSet(RuleSet), /// A multiline comment: `/* foo bar */` MultilineComment(String), + /// A CSS rule: `@charset "UTF-8";` + AtRule(AtRule), } /// 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 { selector: Selector, rules: Vec, @@ -415,6 +417,7 @@ impl<'a> StyleSheetParser<'a> { AtRule::Function(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::Warn(pos, message) => self.warn(pos, &message), AtRule::Debug(pos, message) => self.debug(pos, &message), @@ -568,6 +571,7 @@ pub(crate) fn eat_expr>( return match AtRule::from_tokens(rule, pos, toks, scope) { AtRule::Mixin(name, mixin) => Ok(Some(Expr::MixinDecl(name, *mixin))), 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::Warn(a, b) => Ok(Some(Expr::Warn(a, b))), AtRule::Error(a, b) => Err((a, b)),