Refactor AtRule parsing and parse @return

This commit is contained in:
ConnorSkees 2020-01-25 13:49:25 -05:00
parent a3c668ae83
commit cdd0ccca16
2 changed files with 84 additions and 71 deletions

View File

@ -1,17 +1,87 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::iter::Peekable;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use crate::common::Pos; use crate::{Token, TokenKind};
use crate::common::{Pos, Scope, Symbol};
use crate::function::Function; use crate::function::Function;
use crate::mixin::Mixin; use crate::mixin::Mixin;
use crate::utils::devour_whitespace;
use crate::value::Value;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum AtRule { pub(crate) enum AtRule {
Error(Pos, String), Error(Pos, String),
Warn(Pos, String), Warn(Pos, String),
Debug(Pos, String), Debug(Pos, String),
Mixin(String, Mixin), Mixin(String, Box<Mixin>),
Function(String, Function), Function(String, Box<Function>),
Return(Value),
}
impl AtRule {
pub fn from_tokens<I: Iterator<Item = Token>>(
rule: &AtRuleKind,
pos: Pos,
toks: &mut Peekable<I>,
scope: &Scope,
) -> AtRule {
devour_whitespace(toks);
match rule {
AtRuleKind::Error => {
let message = toks
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
AtRule::Error(pos, message)
}
AtRuleKind::Warn => {
let message = toks
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
devour_whitespace(toks);
AtRule::Warn(pos, message)
}
AtRuleKind::Debug => {
let message = toks
.by_ref()
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
devour_whitespace(toks);
AtRule::Debug(pos, message)
}
AtRuleKind::Mixin => {
let (name, mixin) = match Mixin::decl_from_tokens(toks, scope) {
Ok(m) => m,
Err(e) => return AtRule::Error(e.0, e.1),
};
AtRule::Mixin(name, Box::new(mixin))
}
AtRuleKind::Function => {
let (name, func) = match Function::decl_from_tokens(toks, scope) {
Ok(m) => m,
Err(e) => return AtRule::Error(e.0, e.1),
};
AtRule::Function(name, Box::new(func))
}
AtRuleKind::Return => AtRule::Return(Value::from_tokens(toks, scope).unwrap()),
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::Each => todo!("@each not yet implemented"),
AtRuleKind::Extend => todo!("@extend not yet implemented"),
AtRuleKind::If => todo!("@if not yet implemented"),
AtRuleKind::Else => todo!("@else not yet implemented"),
AtRuleKind::For => todo!("@for not yet implemented"),
AtRuleKind::While => todo!("@while not yet implemented"),
AtRuleKind::Media => todo!("@media not yet implemented"),
AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"),
_ => todo!("encountered unimplemented at rule"),
}
}
} }
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
@ -27,6 +97,7 @@ pub enum AtRuleKind {
Include, Include,
/// Defines custom functions that can be used in SassScript expressions /// Defines custom functions that can be used in SassScript expressions
Function, Function,
Return,
/// Allows selectors to inherit styles from one another /// Allows selectors to inherit styles from one another
Extend, Extend,
/// Puts styles within it at the root of the CSS document /// Puts styles within it at the root of the CSS document
@ -94,6 +165,7 @@ impl TryFrom<&str> for AtRuleKind {
"mixin" => Ok(Self::Mixin), "mixin" => Ok(Self::Mixin),
"include" => Ok(Self::Include), "include" => Ok(Self::Include),
"function" => Ok(Self::Function), "function" => Ok(Self::Function),
"return" => Ok(Self::Return),
"extend" => Ok(Self::Extend), "extend" => Ok(Self::Extend),
"atroot" => Ok(Self::AtRoot), "atroot" => Ok(Self::AtRoot),
"error" => Ok(Self::Error), "error" => Ok(Self::Error),
@ -135,6 +207,7 @@ impl Display for AtRuleKind {
Self::Mixin => write!(f, "@mixin"), Self::Mixin => write!(f, "@mixin"),
Self::Include => write!(f, "@include"), Self::Include => write!(f, "@include"),
Self::Function => write!(f, "@function"), Self::Function => write!(f, "@function"),
Self::Return => write!(f, "@return"),
Self::Extend => write!(f, "@extend"), Self::Extend => write!(f, "@extend"),
Self::AtRoot => write!(f, "@atroot"), Self::AtRoot => write!(f, "@atroot"),
Self::Error => write!(f, "@error"), Self::Error => write!(f, "@error"),

View File

@ -406,12 +406,13 @@ impl<'a> StyleSheetParser<'a> {
pos, pos,
}) = self.lexer.next() }) = self.lexer.next()
{ {
match eat_at_rule(rule, pos, &mut self.lexer, &self.global_scope) { match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope) {
AtRule::Mixin(name, mixin) => {self.global_scope.mixins.insert(name, mixin);}, AtRule::Mixin(name, mixin) => {self.global_scope.mixins.insert(name, *mixin);},
AtRule::Function(name, func) => {self.global_scope.functions.insert(name, func);}, AtRule::Function(name, func) => {self.global_scope.functions.insert(name, *func);},
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),
AtRule::Return(_) => todo!("@return in unexpected location!"),
} }
} }
} }
@ -468,68 +469,6 @@ impl<'a> StyleSheetParser<'a> {
} }
} }
fn eat_at_rule<I: Iterator<Item = Token>>(
rule: &AtRuleKind,
pos: Pos,
toks: &mut Peekable<I>,
scope: &Scope,
) -> AtRule {
devour_whitespace(toks);
match rule {
AtRuleKind::Error => {
let message = toks
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
AtRule::Error(pos, message)
}
AtRuleKind::Warn => {
let message = toks
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
devour_whitespace(toks);
AtRule::Warn(pos, message)
}
AtRuleKind::Debug => {
let message = toks
.by_ref()
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
.map(|x| x.kind.to_string())
.collect::<String>();
devour_whitespace(toks);
AtRule::Debug(pos, message)
}
AtRuleKind::Mixin => {
let (name, mixin) = match Mixin::decl_from_tokens(toks, scope) {
Ok(m) => m,
Err(e) => return AtRule::Error(e.0, e.1),
};
AtRule::Mixin(name, mixin)
}
AtRuleKind::Function => {
let (name, mixin) = match Function::decl_from_tokens(toks, scope) {
Ok(m) => m,
Err(e) => return AtRule::Error(e.0, e.1),
};
AtRule::Function(name, mixin)
}
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::Each => todo!("@each not yet implemented"),
AtRuleKind::Extend => todo!("@extend not yet implemented"),
AtRuleKind::If => todo!("@if not yet implemented"),
AtRuleKind::Else => todo!("@else not yet implemented"),
AtRuleKind::For => todo!("@for not yet implemented"),
AtRuleKind::While => todo!("@while not yet implemented"),
AtRuleKind::Media => todo!("@media not yet implemented"),
AtRuleKind::Keyframes => todo!("@keyframes not yet implemented"),
_ => todo!("encountered unimplemented at rule"),
}
}
pub(crate) fn eat_expr<I: Iterator<Item = Token>>( pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
toks: &mut Peekable<I>, toks: &mut Peekable<I>,
scope: &Scope, scope: &Scope,
@ -617,12 +556,13 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
pos, pos,
}) = toks.next() }) = toks.next()
{ {
return match eat_at_rule(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::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)),
AtRule::Return(_) => todo!("@return in unexpected location!"),
} }
} }
} }