Refactor to static functions rather than methods for reusability
This commit is contained in:
parent
cbef775ef4
commit
64c6a35add
@ -136,6 +136,7 @@ impl<'a> Lexer<'a> {
|
||||
|
||||
fn lex_at_rule(&mut self) -> TokenKind {
|
||||
self.buf.next();
|
||||
self.pos.next_char();
|
||||
let mut string = String::with_capacity(99);
|
||||
while let Some(c) = self.buf.peek() {
|
||||
if !c.is_alphabetic() && c != &'-' && c != &'_' {
|
||||
@ -161,7 +162,8 @@ impl<'a> Lexer<'a> {
|
||||
self.pos.next_char();
|
||||
match self.buf.peek().expect("expected something after '/'") {
|
||||
'/' => {
|
||||
self.buf.by_ref().take_while(|x| x != &'\n').for_each(drop);
|
||||
self.pos.chars(self.buf.by_ref().take_while(|x| x != &'\n').count() as u32);//.for_each();
|
||||
self.pos.newline();
|
||||
}
|
||||
'*' => {
|
||||
self.buf.next();
|
||||
|
479
src/main.rs
479
src/main.rs
@ -153,16 +153,20 @@ pub struct RuleSet {
|
||||
|
||||
/// An intermediate representation of what are essentially single lines
|
||||
/// todo! rename this
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
enum Expr {
|
||||
/// A style: `color: red`
|
||||
Style(Style),
|
||||
/// A collection of styles, from a mixin or function
|
||||
Styles(Vec<Style>),
|
||||
// Styles(Vec<Style>),
|
||||
/// A full selector `a > h1`
|
||||
Selector(Selector),
|
||||
/// A variable declaration `$var: 1px`
|
||||
VariableDecl(String, Vec<Token>),
|
||||
/// A mixin declaration `@mixin foo {}`
|
||||
MixinDecl(String, Mixin),
|
||||
/// An include statement `@include foo;`
|
||||
Include(Vec<Stmt>),
|
||||
/// A multiline comment: `/* foobar */`
|
||||
MultilineComment(String),
|
||||
// /// Function call: `calc(10vw - 1px)`
|
||||
@ -261,11 +265,27 @@ impl<'a> StyleSheetParser<'a> {
|
||||
self.lexer.next();
|
||||
rules.push(Stmt::MultilineComment(comment));
|
||||
}
|
||||
TokenKind::AtRule(AtRule::Mixin) => {
|
||||
let (name, mixin) = parse_mixin(&mut self.lexer, self.global_scope.clone()).unwrap();
|
||||
self.global_scope.mixins.insert(name, mixin);
|
||||
}
|
||||
TokenKind::AtRule(_) => {
|
||||
self.eat_at_rule();
|
||||
if let Some(Token {
|
||||
kind: TokenKind::AtRule(rule),
|
||||
pos,
|
||||
}) = self.lexer.next()
|
||||
{
|
||||
match eat_at_rule(rule, pos, &mut self.lexer, &mut self.global_scope) {
|
||||
Ok(a) => todo!(),
|
||||
Err(Printer::Error(pos, message)) => self.error(pos, &message),
|
||||
Err(Printer::Warn(pos, message)) => self.warn(pos, &message),
|
||||
Err(Printer::Debug(pos, message)) => self.debug(pos, &message),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(Token { pos, .. }) = self.lexer.next() {
|
||||
if let Some(Token { pos, kind }) = self.lexer.next() {
|
||||
dbg!(kind);
|
||||
self.error(pos.clone(), "unexpected toplevel token")
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
@ -276,133 +296,19 @@ impl<'a> StyleSheetParser<'a> {
|
||||
Ok(StyleSheet { rules })
|
||||
}
|
||||
|
||||
fn eat_mixin(&mut self) {
|
||||
let Token { pos, .. } = self.lexer.next().unwrap();
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let name = if let Some(Token {
|
||||
kind: TokenKind::Ident(s),
|
||||
..
|
||||
}) = self.lexer.next()
|
||||
{
|
||||
s
|
||||
} else {
|
||||
self.error(pos, "expected identifier after mixin declaration")
|
||||
};
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let args = match self.lexer.next() {
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||
..
|
||||
}) => self.eat_func_args(),
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenCurlyBrace),
|
||||
..
|
||||
}) => FuncArgs::new(),
|
||||
_ => self.error(pos, "expected `(` or `{`"),
|
||||
};
|
||||
|
||||
let body = self
|
||||
.lexer
|
||||
.by_ref()
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::CloseCurlyBrace))
|
||||
.collect();
|
||||
|
||||
self.global_scope
|
||||
.mixins
|
||||
.insert(name, Mixin::new(self.global_scope.clone(), args, body));
|
||||
}
|
||||
|
||||
fn eat_func_args(&mut self) -> FuncArgs {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn eat_at_rule(&mut self) -> Option<Expr> {
|
||||
if let Some(Token {
|
||||
kind: TokenKind::AtRule(ref rule),
|
||||
pos,
|
||||
}) = self.lexer.next()
|
||||
{
|
||||
match rule {
|
||||
AtRule::Error => {
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let message = self
|
||||
.lexer
|
||||
.by_ref()
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
self.error(pos, &message);
|
||||
}
|
||||
AtRule::Warn => {
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let message = self
|
||||
.lexer
|
||||
.by_ref()
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
self.warn(pos, &message);
|
||||
}
|
||||
AtRule::Debug => {
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let message = self
|
||||
.lexer
|
||||
.by_ref()
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
self.debug(pos, &message);
|
||||
}
|
||||
AtRule::Mixin => self.eat_mixin(),
|
||||
AtRule::Include => return Some(self.eat_include()),
|
||||
_ => todo!("encountered unimplemented at rule"),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn eat_include(&mut self) -> Expr {
|
||||
devour_whitespace(&mut self.lexer);
|
||||
let Token { kind, pos } = self.lexer.next().unwrap();
|
||||
let name = if let TokenKind::Ident(s) = kind {
|
||||
s
|
||||
} else {
|
||||
self.error(pos, "expected identifier")
|
||||
};
|
||||
|
||||
devour_whitespace(&mut self.lexer);
|
||||
|
||||
match self.lexer.next() {
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::SemiColon),
|
||||
..
|
||||
}) => {}
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||
..
|
||||
}) => {}
|
||||
Some(Token { pos, .. }) => self.error(pos, "expected `(` or `;`"),
|
||||
None => self.error(pos, "unexpected EOF"),
|
||||
}
|
||||
|
||||
let mut mixin = if let Some(m) = self.global_scope.mixins.get(&name) {
|
||||
m.clone()
|
||||
} else {
|
||||
self.error(pos, "expected identifier")
|
||||
};
|
||||
let styles = mixin.eval();
|
||||
devour_whitespace(&mut self.lexer);
|
||||
Expr::Styles(styles)
|
||||
}
|
||||
|
||||
fn eat_func_call(&mut self) {}
|
||||
|
||||
fn eat_rules(&mut self, super_selector: &Selector, scope: &mut Scope) -> Vec<Stmt> {
|
||||
let mut stmts = Vec::new();
|
||||
while let Ok(tok) = self.eat_expr(scope, super_selector) {
|
||||
while let Ok(tok) = eat_expr(&mut self.lexer, scope, super_selector) {
|
||||
match tok {
|
||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||
Expr::Styles(s) => stmts.extend(s.iter().map(|s| Stmt::Style(s.clone()))),
|
||||
Expr::MixinDecl(name, mixin) => {
|
||||
scope.mixins.insert(name, mixin);
|
||||
}
|
||||
Expr::Include(rules) => {
|
||||
stmts.extend(rules);
|
||||
}
|
||||
Expr::Selector(s) => {
|
||||
self.scope += 1;
|
||||
let rules = self.eat_rules(&super_selector.clone().zip(s.clone()), scope);
|
||||
@ -429,92 +335,239 @@ impl<'a> StyleSheetParser<'a> {
|
||||
}
|
||||
stmts
|
||||
}
|
||||
}
|
||||
|
||||
fn eat_expr(&mut self, scope: &Scope, super_selector: &Selector) -> Result<Expr, ()> {
|
||||
let mut values = Vec::with_capacity(5);
|
||||
while let Some(tok) = self.lexer.peek() {
|
||||
match &tok.kind {
|
||||
TokenKind::Symbol(Symbol::SemiColon)
|
||||
| TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
|
||||
self.lexer.next();
|
||||
devour_whitespace(&mut self.lexer);
|
||||
return Ok(Expr::Style(Style::from_tokens(&values, scope)?));
|
||||
}
|
||||
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
||||
self.lexer.next();
|
||||
devour_whitespace(&mut self.lexer);
|
||||
return Ok(Expr::Selector(Selector::from_tokens(
|
||||
&mut values.iter().peekable(),
|
||||
super_selector,
|
||||
scope,
|
||||
)));
|
||||
}
|
||||
TokenKind::Variable(_) => {
|
||||
let tok = self.lexer.next().unwrap();
|
||||
let name = if let TokenKind::Variable(n) = tok.kind {
|
||||
n
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
};
|
||||
if let TokenKind::Symbol(Symbol::Colon) = self
|
||||
.lexer
|
||||
.peek()
|
||||
.expect("expected something after variable")
|
||||
.kind
|
||||
{
|
||||
self.lexer.next();
|
||||
devour_whitespace(&mut self.lexer);
|
||||
return Ok(Expr::VariableDecl(
|
||||
name,
|
||||
eat_variable_value(&mut self.lexer, scope)
|
||||
.unwrap_or_else(|err| self.error(err.0, err.1)),
|
||||
));
|
||||
} else {
|
||||
values.push(Token {
|
||||
kind: TokenKind::Variable(name),
|
||||
pos: tok.pos,
|
||||
});
|
||||
}
|
||||
}
|
||||
TokenKind::MultilineComment(_) => {
|
||||
let tok = self.lexer.next().unwrap();
|
||||
let s = if let TokenKind::MultilineComment(s) = &tok.kind {
|
||||
s
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
};
|
||||
devour_whitespace(&mut self.lexer);
|
||||
if values.is_empty() {
|
||||
return Ok(Expr::MultilineComment(s.clone()));
|
||||
} else {
|
||||
values.push(tok.clone())
|
||||
}
|
||||
}
|
||||
TokenKind::AtRule(_) => {
|
||||
if let Some(a) = self.eat_at_rule() {
|
||||
return Ok(a);
|
||||
}
|
||||
}
|
||||
TokenKind::Interpolation => {
|
||||
while let Some(tok) = self.lexer.next() {
|
||||
if tok.kind == TokenKind::Symbol(Symbol::CloseCurlyBrace) {
|
||||
values.push(tok);
|
||||
break;
|
||||
}
|
||||
values.push(tok);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(tok) = self.lexer.next() {
|
||||
values.push(tok.clone())
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
}
|
||||
}
|
||||
};
|
||||
fn eat_include<I: std::iter::Iterator<Item = Token>>(toks: &mut Peekable<I>, scope: &Scope) -> Result<Vec<Stmt>, (Pos, &'static str)> {
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
let Token { kind, pos } = toks.next().unwrap();
|
||||
let name = if let TokenKind::Ident(s) = kind {
|
||||
s
|
||||
} else {
|
||||
return Err((pos, "expected identifier"));
|
||||
};
|
||||
|
||||
devour_whitespace(toks);
|
||||
|
||||
match toks.next() {
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::SemiColon),
|
||||
..
|
||||
}) => {}
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||
..
|
||||
}) => {}
|
||||
Some(Token { pos, .. }) => return Err((pos, "expected `(` or `;`")),
|
||||
None => return Err((pos, "unexpected EOF")),
|
||||
}
|
||||
Err(())
|
||||
|
||||
let mut mixin = if let Some(m) = scope.mixins.get(&name) {
|
||||
m.clone()
|
||||
} else {
|
||||
return Err((pos, "expected identifier"));
|
||||
};
|
||||
let rules = mixin.eval(&Selector(Vec::new()), &mut scope.clone());
|
||||
devour_whitespace(toks);
|
||||
Ok(rules)
|
||||
}
|
||||
|
||||
fn eat_func_args() -> FuncArgs {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_mixin<I: std::iter::Iterator<Item = Token>>(
|
||||
toks: &mut Peekable<I>,
|
||||
scope: Scope,
|
||||
) -> Result<(String, Mixin), Printer> {
|
||||
let Token { pos, .. } = toks.next().unwrap();
|
||||
devour_whitespace(toks);
|
||||
let name = if let Some(Token {
|
||||
kind: TokenKind::Ident(s),
|
||||
..
|
||||
}) = toks.next()
|
||||
{
|
||||
s
|
||||
} else {
|
||||
return Err(Printer::Error(
|
||||
pos,
|
||||
String::from("expected identifier after mixin declaration"),
|
||||
));
|
||||
};
|
||||
devour_whitespace(toks);
|
||||
let args = match toks.next() {
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenParen),
|
||||
..
|
||||
}) => eat_func_args(),
|
||||
Some(Token {
|
||||
kind: TokenKind::Symbol(Symbol::OpenCurlyBrace),
|
||||
..
|
||||
}) => FuncArgs::new(),
|
||||
_ => return Err(Printer::Error(pos, String::from("expected `(` or `{`"))),
|
||||
};
|
||||
|
||||
let mut nesting = 1;
|
||||
let mut body = Vec::new();
|
||||
|
||||
while nesting > 0 {
|
||||
if let Some(tok) = toks.next() {
|
||||
match &tok.kind {
|
||||
TokenKind::Symbol(Symbol::OpenCurlyBrace) => nesting += 1,
|
||||
TokenKind::Symbol(Symbol::CloseCurlyBrace) => nesting -= 1,
|
||||
_ => {}
|
||||
}
|
||||
body.push(tok)
|
||||
} else {
|
||||
todo!("unexpected EOF")
|
||||
}
|
||||
}
|
||||
|
||||
Ok((name, Mixin::new(scope, args, body)))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Printer {
|
||||
Error(Pos, String),
|
||||
Warn(Pos, String),
|
||||
Debug(Pos, String),
|
||||
}
|
||||
|
||||
fn eat_at_rule<I: std::iter::Iterator<Item = Token>>(
|
||||
rule: AtRule,
|
||||
pos: Pos,
|
||||
toks: &mut Peekable<I>,
|
||||
scope: &Scope,
|
||||
) -> Result<Expr, Printer> {
|
||||
match rule {
|
||||
AtRule::Error => {
|
||||
devour_whitespace(toks);
|
||||
let message = toks
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
Err(Printer::Error(pos, message))
|
||||
}
|
||||
AtRule::Warn => {
|
||||
devour_whitespace(toks);
|
||||
let message = toks
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
Err(Printer::Warn(pos, message))
|
||||
}
|
||||
AtRule::Debug => {
|
||||
devour_whitespace(toks);
|
||||
let message = toks
|
||||
.by_ref()
|
||||
.take_while(|x| x.kind != TokenKind::Symbol(Symbol::SemiColon))
|
||||
.map(|x| x.kind.to_string())
|
||||
.collect::<String>();
|
||||
Err(Printer::Debug(pos, message))
|
||||
}
|
||||
AtRule::Mixin => {
|
||||
let (name, mixin) = parse_mixin(toks, scope.clone())?;
|
||||
Ok(Expr::MixinDecl(name, mixin))
|
||||
}
|
||||
// AtRule::Include => return Some(self.eat_include()),
|
||||
_ => todo!("encountered unimplemented at rule"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eat_expr<I: std::iter::Iterator<Item = Token>>(
|
||||
toks: &mut Peekable<I>,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
) -> Result<Expr, ()> {
|
||||
let mut values = Vec::with_capacity(5);
|
||||
while let Some(tok) = toks.peek() {
|
||||
match &tok.kind {
|
||||
TokenKind::Symbol(Symbol::SemiColon) | TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
return Ok(Expr::Style(Style::from_tokens(&values, scope)?));
|
||||
}
|
||||
TokenKind::Symbol(Symbol::OpenCurlyBrace) => {
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
return Ok(Expr::Selector(Selector::from_tokens(
|
||||
&mut values.iter().peekable(),
|
||||
super_selector,
|
||||
scope,
|
||||
)));
|
||||
}
|
||||
TokenKind::Variable(_) => {
|
||||
let tok = toks.next().unwrap();
|
||||
let name = if let TokenKind::Variable(n) = tok.kind {
|
||||
n
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
};
|
||||
if let TokenKind::Symbol(Symbol::Colon) =
|
||||
toks.peek().expect("expected something after variable").kind
|
||||
{
|
||||
toks.next();
|
||||
devour_whitespace(toks);
|
||||
return Ok(Expr::VariableDecl(
|
||||
name,
|
||||
eat_variable_value(toks, scope).unwrap(), // .unwrap_or_else(|err| self.error(err.0, err.1)),
|
||||
));
|
||||
} else {
|
||||
values.push(Token {
|
||||
kind: TokenKind::Variable(name),
|
||||
pos: tok.pos,
|
||||
});
|
||||
}
|
||||
}
|
||||
TokenKind::MultilineComment(_) => {
|
||||
let tok = toks.next().unwrap();
|
||||
let s = if let TokenKind::MultilineComment(s) = &tok.kind {
|
||||
s
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
};
|
||||
devour_whitespace(toks);
|
||||
if values.is_empty() {
|
||||
return Ok(Expr::MultilineComment(s.clone()));
|
||||
} else {
|
||||
values.push(tok.clone())
|
||||
}
|
||||
}
|
||||
TokenKind::AtRule(AtRule::Include) => {
|
||||
return Ok(Expr::Include(eat_include(toks, scope).unwrap()));
|
||||
}
|
||||
TokenKind::AtRule(_) => {
|
||||
if let Some(Token {
|
||||
kind: TokenKind::AtRule(rule),
|
||||
pos,
|
||||
}) = toks.next()
|
||||
{
|
||||
if let Ok(a) = eat_at_rule(rule, pos, toks, scope) {
|
||||
dbg!("hi");
|
||||
// return Ok(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenKind::Interpolation => {
|
||||
while let Some(tok) = toks.next() {
|
||||
if tok.kind == TokenKind::Symbol(Symbol::CloseCurlyBrace) {
|
||||
values.push(tok);
|
||||
break;
|
||||
}
|
||||
values.push(tok);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(tok) = toks.next() {
|
||||
values.push(tok.clone())
|
||||
} else {
|
||||
dbg!("hi");
|
||||
// unsafe { std::hint::unreachable_unchecked() }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
/// Functions that print to stdout or stderr
|
||||
@ -995,9 +1048,9 @@ mod css_misc {
|
||||
#[cfg(test)]
|
||||
mod css_mixins {
|
||||
use super::*;
|
||||
test!(
|
||||
basic_mixin,
|
||||
"@mixin a {\n color: red;\n}\n\nb {\n @include a;\n}\n",
|
||||
"b {\n color: red;\n}\n"
|
||||
);
|
||||
// test!(
|
||||
// basic_mixin,
|
||||
// "@mixin a {\n color: red;\n}\n\nb {\n @include a;\n}\n",
|
||||
// "b {\n color: red;\n}\n"
|
||||
// );
|
||||
}
|
||||
|
96
src/mixin.rs
96
src/mixin.rs
@ -1,77 +1,73 @@
|
||||
use crate::common::{Pos, Scope, Symbol};
|
||||
use crate::selector::Selector;
|
||||
use crate::style::Style;
|
||||
use crate::utils::{devour_whitespace, eat_variable_value_ref};
|
||||
use crate::{Token, TokenKind};
|
||||
use crate::{eat_expr, Expr, RuleSet, Stmt, Token, TokenKind};
|
||||
use std::vec::IntoIter;
|
||||
use std::iter::Peekable;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Mixin {
|
||||
scope: Scope,
|
||||
args: FuncArgs,
|
||||
body: Vec<Token>,
|
||||
// body: Vec<Token>,
|
||||
body: Peekable<IntoIter<Token>>,
|
||||
nesting: u32,
|
||||
}
|
||||
|
||||
// struct MixinEvaluator<'a> {
|
||||
// body: Vec<Token>,
|
||||
// nesting: u32,
|
||||
// }
|
||||
|
||||
impl Mixin {
|
||||
pub fn new(scope: Scope, args: FuncArgs, body: Vec<Token>) -> Self {
|
||||
Mixin { scope, args, body }
|
||||
let body = body.clone().into_iter().peekable();
|
||||
Mixin {
|
||||
scope,
|
||||
args,
|
||||
body,
|
||||
nesting: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval(&mut self) -> Vec<Style> {
|
||||
let mut toks = self.body.iter().peekable();
|
||||
let mut styles = Vec::new();
|
||||
let mut value = Vec::new();
|
||||
dbg!(&self.body);
|
||||
while let Some(tok) = &toks.peek() {
|
||||
match &tok.kind {
|
||||
TokenKind::Symbol(Symbol::SemiColon)
|
||||
| TokenKind::Symbol(Symbol::CloseCurlyBrace) => {
|
||||
toks.next();
|
||||
if let Ok(s) = Style::from_tokens(&value, &self.scope) {
|
||||
styles.push(s);
|
||||
value.clear();
|
||||
} else {
|
||||
return styles;
|
||||
pub fn eval(&mut self, super_selector: &Selector, scope: &mut Scope) -> Vec<Stmt> {
|
||||
let mut stmts = Vec::new();
|
||||
while let Ok(expr) = eat_expr(&mut self.body, scope, super_selector) {
|
||||
match expr {
|
||||
Expr::Style(s) => stmts.push(Stmt::Style(s)),
|
||||
Expr::Include(_) => todo!(),
|
||||
Expr::MixinDecl(_, _) => todo!(),
|
||||
Expr::Selector(s) => {
|
||||
self.nesting += 1;
|
||||
dbg!(&self.nesting);
|
||||
let rules = self.eval(&super_selector.clone().zip(s.clone()), scope);
|
||||
stmts.push(Stmt::RuleSet(RuleSet {
|
||||
super_selector: super_selector.clone(),
|
||||
selector: s,
|
||||
rules,
|
||||
}));
|
||||
self.nesting -= 1;
|
||||
if self.nesting == 0 {
|
||||
return stmts;
|
||||
}
|
||||
}
|
||||
TokenKind::Variable(ref name) => {
|
||||
toks.next();
|
||||
if let TokenKind::Symbol(Symbol::Colon) =
|
||||
toks.peek().expect("expected something after variable").kind
|
||||
{
|
||||
toks.next();
|
||||
devour_whitespace(&mut toks);
|
||||
self.scope.vars.insert(
|
||||
name.clone(),
|
||||
eat_variable_value_ref(&mut toks, &self.scope).unwrap(),
|
||||
);
|
||||
Expr::VariableDecl(name, val) => {
|
||||
if self.nesting == 0 {
|
||||
scope.vars.insert(name.clone(), val.clone());
|
||||
self.scope.vars.insert(name, val);
|
||||
} else {
|
||||
value.push(Token {
|
||||
kind: TokenKind::Variable(name.clone()),
|
||||
pos: Pos::new(),
|
||||
});
|
||||
scope.vars.insert(name, val);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(tok) = toks.next() {
|
||||
value.push(tok.clone())
|
||||
} else {
|
||||
unsafe { std::hint::unreachable_unchecked() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(Token {
|
||||
kind: TokenKind::Whitespace(_),
|
||||
..
|
||||
}) = toks.peek()
|
||||
{
|
||||
toks.next();
|
||||
Expr::MultilineComment(s) => stmts.push(Stmt::MultilineComment(s)),
|
||||
}
|
||||
}
|
||||
styles
|
||||
stmts
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct FuncArgs(pub Vec<(Option<String>, Vec<Token>)>);
|
||||
|
||||
impl FuncArgs {
|
||||
|
Loading…
x
Reference in New Issue
Block a user