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::iter::Peekable;
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::mixin::Mixin;
use crate::utils::devour_whitespace;
use crate::value::Value;
#[derive(Debug, Clone)]
pub(crate) enum AtRule {
Error(Pos, String),
Warn(Pos, String),
Debug(Pos, String),
Mixin(String, Mixin),
Function(String, Function),
Mixin(String, Box<Mixin>),
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)]
@ -27,6 +97,7 @@ pub enum AtRuleKind {
Include,
/// Defines custom functions that can be used in SassScript expressions
Function,
Return,
/// Allows selectors to inherit styles from one another
Extend,
/// Puts styles within it at the root of the CSS document
@ -94,6 +165,7 @@ impl TryFrom<&str> for AtRuleKind {
"mixin" => Ok(Self::Mixin),
"include" => Ok(Self::Include),
"function" => Ok(Self::Function),
"return" => Ok(Self::Return),
"extend" => Ok(Self::Extend),
"atroot" => Ok(Self::AtRoot),
"error" => Ok(Self::Error),
@ -135,6 +207,7 @@ impl Display for AtRuleKind {
Self::Mixin => write!(f, "@mixin"),
Self::Include => write!(f, "@include"),
Self::Function => write!(f, "@function"),
Self::Return => write!(f, "@return"),
Self::Extend => write!(f, "@extend"),
Self::AtRoot => write!(f, "@atroot"),
Self::Error => write!(f, "@error"),

View File

@ -406,12 +406,13 @@ impl<'a> StyleSheetParser<'a> {
pos,
}) = self.lexer.next()
{
match eat_at_rule(rule, pos, &mut self.lexer, &self.global_scope) {
AtRule::Mixin(name, mixin) => {self.global_scope.mixins.insert(name, mixin);},
AtRule::Function(name, func) => {self.global_scope.functions.insert(name, func);},
match AtRule::from_tokens(rule, pos, &mut self.lexer, &self.global_scope) {
AtRule::Mixin(name, mixin) => {self.global_scope.mixins.insert(name, *mixin);},
AtRule::Function(name, func) => {self.global_scope.functions.insert(name, *func);},
AtRule::Error(pos, message) => self.error(pos, &message),
AtRule::Warn(pos, message) => self.warn(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>>(
toks: &mut Peekable<I>,
scope: &Scope,
@ -617,12 +556,13 @@ pub(crate) fn eat_expr<I: Iterator<Item = Token>>(
pos,
}) = toks.next()
{
return match eat_at_rule(rule, pos, toks, scope) {
AtRule::Mixin(name, mixin) => Ok(Some(Expr::MixinDecl(name, mixin))),
AtRule::Function(name, func) => Ok(Some(Expr::FunctionDecl(name, func))),
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::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)),
AtRule::Return(_) => todo!("@return in unexpected location!"),
}
}
}