Skip to content

Commit

Permalink
feat(css-definition-syntax): support boolean-expr (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
fiji-flo authored Dec 19, 2024
1 parent bdfdb23 commit 18baff1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
9 changes: 9 additions & 0 deletions crates/css-definition-syntax/src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ fn internal_generate<'a>(
let decorated = decorate(multiplier, node);
format!("{}{}", terms, decorated)
}
Node::BooleanExpr(boolean_expr) => {
let terms = internal_generate(&boolean_expr.term, decorate, force_braces, compact)?;
format!("<boolean-expr[{}]>", terms)
}
Node::Token(token) => token.value.to_string(),
Node::Property(property) => format!("<'{}'>", property.name),
Node::Type(typ) => {
Expand Down Expand Up @@ -198,6 +202,11 @@ mod tests {
let node = parse(input)?;
let result = generate(&node, Default::default()).unwrap();
assert_eq!(result, "<calc-product> [ [ '+' | '-' ] <calc-product> ]*");

let input = "<boolean-expr[a | b]>";
let node = parse(input)?;
let result = generate(&node, Default::default()).unwrap();
assert_eq!(result, "<boolean-expr[a | b]>");
Ok(())
}
}
51 changes: 44 additions & 7 deletions crates/css-definition-syntax/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ pub struct Group {
pub disallow_empty: bool,
pub explicit: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BooleanExpr {
pub term: Box<Node>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Node {
Expand All @@ -142,6 +146,7 @@ pub enum Node {
Spaces(Spaces),
AtKeyword(AtKeyword),
Group(Group),
BooleanExpr(BooleanExpr),
}

impl Node {
Expand All @@ -160,6 +165,7 @@ impl Node {
Node::Spaces(_) => "Spaces",
Node::AtKeyword(_) => "AtKeyword",
Node::Group(_) => "Group",
Node::BooleanExpr(_) => "BooleanExpr",
}
}
}
Expand Down Expand Up @@ -474,6 +480,23 @@ fn read_type_range(tokenizer: &mut Tokenizer) -> Result<Node, SyntaxDefinitionEr
fn read_type(tokenizer: &mut Tokenizer) -> Result<Node, SyntaxDefinitionError> {
tokenizer.eat(LESS_THAN_SIGN)?;
let mut name = scan_word(tokenizer, false)?;
if name == "boolean-expr" {
tokenizer.eat(LEFT_SQUARE_BRACKET)?;
let mut implicit_group = read_implicit_group(tokenizer, Some(RIGHT_SQUARE_BRACKET))?;
tokenizer.eat(RIGHT_SQUARE_BRACKET)?;
tokenizer.eat(GREATER_THAN_SIGN)?;

return maybe_multiplied(
tokenizer,
Node::BooleanExpr(BooleanExpr {
term: Box::new(if implicit_group.terms.len() == 1 {
implicit_group.terms.pop().unwrap()
} else {
Node::Group(implicit_group)
}),
}),
);
}

if tokenizer.char_code() == LEFT_PARENTHESIS && tokenizer.next_char_code() == RIGHT_PARENTHESIS
{
Expand Down Expand Up @@ -575,12 +598,15 @@ fn regroup_terms(
(terms, combinator)
}

fn read_implicit_group(tokenizer: &mut Tokenizer) -> Result<Group, SyntaxDefinitionError> {
fn read_implicit_group(
tokenizer: &mut Tokenizer,
stop_char: Option<char>,
) -> Result<Group, SyntaxDefinitionError> {
let mut prev_token_pos = tokenizer.pos;
let mut combinators = HashSet::new();
let mut terms = vec![];

while let Some(token) = peek(tokenizer)? {
while let Some(token) = peek(tokenizer, stop_char)? {
match (&token, terms.last()) {
(Node::Spaces(Spaces { value: _ }), _) => continue,
(
Expand Down Expand Up @@ -618,9 +644,12 @@ fn read_implicit_group(tokenizer: &mut Tokenizer) -> Result<Group, SyntaxDefinit
})
}

fn read_group(tokenizer: &mut Tokenizer) -> Result<Node, SyntaxDefinitionError> {
fn read_group(
tokenizer: &mut Tokenizer,
stop_char: Option<char>,
) -> Result<Node, SyntaxDefinitionError> {
tokenizer.eat(LEFT_SQUARE_BRACKET)?;
let mut group = read_implicit_group(tokenizer)?;
let mut group = read_implicit_group(tokenizer, stop_char)?;
tokenizer.eat(RIGHT_SQUARE_BRACKET)?;

group.explicit = true;
Expand All @@ -633,16 +662,24 @@ fn read_group(tokenizer: &mut Tokenizer) -> Result<Node, SyntaxDefinitionError>
Ok(Node::Group(group))
}

fn peek(tokenizer: &mut Tokenizer) -> Result<Option<Node>, SyntaxDefinitionError> {
fn peek(
tokenizer: &mut Tokenizer,
stop_char: Option<char>,
) -> Result<Option<Node>, SyntaxDefinitionError> {
let code = tokenizer.char_code();
if let Some(stop_char) = stop_char {
if code == stop_char {
return Ok(None);
}
}
if is_name_char(code) {
return Ok(Some(read_keyword_or_function(tokenizer)?));
}

Ok(match code {
RIGHT_SQUARE_BRACKET => None,
LEFT_SQUARE_BRACKET => {
let group = read_group(tokenizer)?;
let group = read_group(tokenizer, stop_char)?;
Some(maybe_multiplied(tokenizer, group)?)
}
LESS_THAN_SIGN => Some(if tokenizer.next_char_code() == APOSTROPHE {
Expand Down Expand Up @@ -710,7 +747,7 @@ fn peek(tokenizer: &mut Tokenizer) -> Result<Option<Node>, SyntaxDefinitionError

pub fn parse(source: &str) -> Result<Node, SyntaxDefinitionError> {
let mut tokenizer = Tokenizer::new(source);
let mut result = read_implicit_group(&mut tokenizer)?;
let mut result = read_implicit_group(&mut tokenizer, None)?;

if tokenizer.pos != tokenizer.str.len() {
return Err(SyntaxDefinitionError::ParseErrorUnexpectedInput);
Expand Down
3 changes: 3 additions & 0 deletions crates/css-definition-syntax/src/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub fn walk<T>(
Node::Multiplier(multiplier) => {
walk(&multiplier.term, options, context)?;
}
Node::BooleanExpr(booleann_exp) => {
walk(&booleann_exp.term, options, context)?;
}
Node::Token(_)
| Node::Property(_)
| Node::Type(_)
Expand Down

0 comments on commit 18baff1

Please sign in to comment.