#![warn( clippy::all, clippy::restriction, clippy::pedantic, clippy::nursery, // clippy::cargo )] #![deny(missing_debug_implementations)] #![allow( dead_code, clippy::pub_enum_variant_names, clippy::implicit_return, clippy::use_self, clippy::missing_docs_in_private_items, clippy::todo, clippy::unreachable, clippy::wildcard_enum_match_arm, clippy::option_expect_used, clippy::panic, clippy::unused_self, clippy::too_many_lines, clippy::integer_arithmetic, clippy::missing_errors_doc, clippy::let_underscore_must_use, clippy::module_name_repetitions )] // todo! handle erroring on styles at the toplevel use std::fmt::{self, Display}; use std::fs; use std::io; use std::iter::{Iterator, Peekable}; use std::path::Path; use crate::common::{AtRule, Keyword, Op, Pos, Printer, Scope, Symbol, Whitespace}; use crate::css::Css; use crate::error::SassError; use crate::format::PrettyPrinter; use crate::function::{eat_call_args, eat_func_args, CallArgs, FuncArgs}; use crate::lexer::Lexer; use crate::mixin::Mixin; use crate::selector::{Attribute, Selector}; use crate::style::Style; use crate::units::Unit; use crate::utils::{devour_whitespace, eat_variable_value, IsWhitespace}; mod color; mod common; mod css; mod error; mod format; mod function; mod imports; mod lexer; mod mixin; mod selector; mod style; mod units; mod utils; type SassResult = Result; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Token { pos: Pos, pub kind: TokenKind, } impl IsWhitespace for Token { fn is_whitespace(&self) -> bool { if let TokenKind::Whitespace(_) = self.kind { return true; } false } } impl IsWhitespace for &Token { fn is_whitespace(&self) -> bool { if let TokenKind::Whitespace(_) = self.kind { return true; } false } } #[derive(Clone, Debug, Eq, PartialEq)] pub enum TokenKind { Ident(String), Symbol(Symbol), AtRule(AtRule), Keyword(Keyword), Number(String), Unit(Unit), Whitespace(Whitespace), Variable(String), Attribute(Attribute), Op(Op), MultilineComment(String), Interpolation, } impl Display for TokenKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TokenKind::Ident(s) | TokenKind::Number(s) => write!(f, "{}", s), TokenKind::Symbol(s) => write!(f, "{}", s), TokenKind::AtRule(s) => write!(f, "{}", s), TokenKind::Op(s) => write!(f, "{}", s), TokenKind::Unit(s) => write!(f, "{}", s), TokenKind::Whitespace(s) => write!(f, "{}", s), TokenKind::Attribute(s) => write!(f, "{}", s), TokenKind::Keyword(kw) => write!(f, "{}", kw), TokenKind::MultilineComment(s) => write!(f, "/*{}*/", s), TokenKind::Variable(s) => write!(f, "${}", s), TokenKind::Interpolation => { panic!("we don't want to format TokenKind::Interpolation using Display") } } } } /// Represents a parsed SASS stylesheet with nesting #[derive(Debug, Clone, Eq, PartialEq)] pub struct StyleSheet { rules: Vec, } #[derive(Clone, Debug, Eq, PartialEq)] pub enum Stmt { /// A [`Style`](/grass/style/struct.Style) Style(Style), /// A [`RuleSet`](/grass/struct.RuleSet.html) RuleSet(RuleSet), /// A multiline comment: `/* foo bar */` MultilineComment(String), } /// Represents a single rule set. Rule sets can contain other rule sets /// /// ```scss /// a { /// color: blue; /// b { /// color: red; /// } /// } /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct RuleSet { selector: Selector, rules: Vec, // potential optimization: we don't *need* to own the selector super_selector: Selector, } /// An intermediate representation of what are essentially single lines /// todo! rename this #[derive(Clone, Debug)] enum Expr { /// A style: `color: red` Style(Style), /// A collection of styles, from a mixin or function // Styles(Vec