Skip to content

Commit

Permalink
Merge pull request #228 from gosub-browser/ahmed/parser-out-1
Browse files Browse the repository at this point in the history
feat(css): parse css rules
  • Loading branch information
neuodev authored Nov 4, 2023
2 parents 4051d40 + 6da782a commit 8fdd0f0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 20 deletions.
97 changes: 77 additions & 20 deletions src/css3/new_parser.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
use super::new_tokenizer::{Token, TokenKind};
use crate::{bytes::CharIterator, css3::new_tokenizer::Tokenizer};

#[derive(Debug, PartialEq)]
struct Function {
name: String,
value: Vec<ComponentValue>,
}

#[derive(Debug, PartialEq)]
enum SimpleBlockTokenKind {
Curly,
Bracket,
Paren,
}

#[derive(Debug, PartialEq)]
struct SimpleBlock {
kind: SimpleBlockTokenKind,
value: Vec<ComponentValue>,
}

#[derive(Debug, PartialEq)]
struct AtRule {
name: String,
prelude: Vec<ComponentValue>,
block: Option<SimpleBlock>,
}

#[derive(Debug, PartialEq)]
struct QualifiedRule {
prelude: Vec<ComponentValue>,
block: SimpleBlock,
}

#[derive(Debug, PartialEq)]
struct Declaration {
name: String,
value: Vec<ComponentValue>,
important: bool,
}

#[derive(Debug, PartialEq)]
enum ComponentValue {
/// Any token expect for `<function-token>`, `<{-token>`, `<(-token>`, and `<[-token>` (which are consumed in other higher-level objects)
///
Expand Down Expand Up @@ -67,50 +74,100 @@ impl<'stream> CSS3Parser<'stream> {
todo!()
}

/// [5.4.9. Consume a function](https://www.w3.org/TR/css-syntax-3/#consume-function)
fn consume_function(&mut self) {
let _name = self.consume_token(TokenKind::Function).value();
/// [5.4.6. Consume a declaration](https://www.w3.org/TR/css-syntax-3/#consume-declaration)
fn consume_declaration(&mut self) -> Option<Declaration> {
let name = self.consume_token(TokenKind::Any).value();
let mut value = Vec::new();

loop {
let token = self.tokenizer.consume();
while self.current_token().is_whitespace() {
self.consume_token(TokenKind::Any);
}

if token.kind() == TokenKind::LParen || token.is_eof() {
break;
}
// parser error
if self.current_token().kind() != TokenKind::Semicolon {
return None;
}

value.push(token);
self.consume_token(TokenKind::Semicolon);

while self.current_token().is_whitespace() {
self.consume_token(TokenKind::Any);
}

while !self.current_token().is_eof() {
value.push(self.consume_component_value())
}

let len = value.len();

let important = len > 2
&& value.last()
== Some(&ComponentValue::Token(Token::Ident(
"important".to_string(),
)))
&& value.get(len - 2) == Some(&ComponentValue::Token(Token::Delim('!')));

Some(Declaration {
name,
value,
important,
})
}

/// [5.4.7. Consume a component value](https://www.w3.org/TR/css-syntax-3/#consume-a-component-value)
fn consume_component_value(&mut self) {}
fn consume_component_value(&mut self) -> ComponentValue {
let token = self.consume_token(TokenKind::Any);

/// [5.4.8. Consume a simple block](https://www.w3.org/TR/css-syntax-3/#consume-a-simple-block)
fn consume_simple_block(&mut self) {
let start = self.current_token().kind();
// consume block start <{-token>, <[-token>, or <(-token>.
self.consume_token(start);
match token.kind() {
TokenKind::LCurly | TokenKind::LBracket | TokenKind::LParen => {
ComponentValue::SimpleBlock(self.consume_simple_block(token.kind()))
}
TokenKind::Function => ComponentValue::Function(self.consume_function()),
_ => ComponentValue::Token(token),
}
}

/// [5.4.8. Consume a simple block](https://www.w3.org/TR/css-syntax-3/#consume-a-simple-block)
fn consume_simple_block(&mut self, ending: TokenKind) -> SimpleBlock {
let mut value = Vec::new();

loop {
// eof: parser error
if self.current_token().kind() == start || self.current_token().is_eof() {
if self.current_token().kind() == ending || self.current_token().is_eof() {
break;
}

// todo: handle "component value" creation from a simple block

value.push(self.consume_token(TokenKind::Any))
value.push(self.consume_component_value())
}

let _kind = match start {
let kind = match ending {
TokenKind::LParen => SimpleBlockTokenKind::Paren,
TokenKind::LCurly => SimpleBlockTokenKind::Curly,
TokenKind::LBracket => SimpleBlockTokenKind::Bracket,
_ => todo!(),
};

SimpleBlock { kind, value }
}

/// [5.4.9. Consume a function](https://www.w3.org/TR/css-syntax-3/#consume-function)
fn consume_function(&mut self) -> Function {
let name = self.consume_token(TokenKind::Function).value();
let mut value = Vec::new();

loop {
let token = self.current_token();

if token.kind() == TokenKind::LParen || token.is_eof() {
// consume `(` or `EOF`
self.consume_token(TokenKind::Any);
break;
}

value.push(self.consume_component_value());
}

Function { name, value }
}

fn current_token(&self) -> Token {
Expand Down
4 changes: 4 additions & 0 deletions src/css3/new_tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ impl Token {
self.kind() == TokenKind::EOF
}

pub fn is_whitespace(&self) -> bool {
self.kind() == TokenKind::Whitespace
}

pub fn value(&self) -> String {
match self {
Token::Function(val) => val.clone(),
Expand Down

0 comments on commit 8fdd0f0

Please sign in to comment.