Skip to content

Commit

Permalink
(ast/selector) rewrite nth selector parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Nov 10, 2024
1 parent f306dd8 commit 51e294a
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 97 deletions.
163 changes: 71 additions & 92 deletions crates/hdx_ast/src/css/selector/nth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use hdx_atom::atom;
use hdx_lexer::Include;
use hdx_lexer::{Include, Kind};
use hdx_parser::{diagnostics, Parse, Parser, Result as ParserResult, Token};
use hdx_writer::{CssWriter, Result as WriterResult, WriteCss};

Expand All @@ -12,15 +12,6 @@ impl<'a> Parse<'a> for Nth {
if let Some(token) = parser.peek::<Token![Number]>() {
parser.hop(token);
return Ok(Self(0, parser.parse_number(token) as i32));
}

let mut b_sign = 0;
let a = if let Some(token) = parser.peek::<Token![Dimension]>() {
if token.is_float() {
Err(diagnostics::ExpectedInt(parser.parse_number(token), token.span()))?
}
parser.hop(token);
parser.parse_number(token) as i32
} else if let Some(token) = parser.peek::<Token![Ident]>() {
match parser.parse_atom_lower(token) {
atom!("even") => {
Expand All @@ -31,101 +22,85 @@ impl<'a> Parse<'a> for Nth {
parser.hop(token);
return Ok(Self(2, 1));
}
atom!("-n") => {
parser.hop(token);
-1
}
atom!("n") => {
parser.hop(token);
1
}
atom!("n-") => {
parser.hop(token);
b_sign = -1;
1
}
anb => {
if anb.starts_with('-') {
-1
} else {
1
}
}
_ => {}
}
} else {
parser.parse::<Token![Delim]>()?;
if let Some(next) = parser.peek_with::<Token![Ident]>(Include::Whitespace) {
let anb = parser.parse_atom_lower(next);
if !anb.starts_with('n') {
Err(diagnostics::UnexpectedIdent(anb, next.span()))?
}
1
} else {
let token = parser.peek::<Token![Any]>().unwrap();
Err(diagnostics::ExpectedIdent(token, token.span()))?
}
};
let mut token = None;
if let Some(t) = parser.peek::<Token![Ident]>() {
parser.hop(t);
token = Some(t);
} else if let Some(t) = parser.peek::<Token![Dimension]>() {
parser.hop(t);
token = Some(t);
}
let b = if let Some(token) = token {
let str = parser.parse_str(token);
let mut chars = str.chars();
if str.starts_with('-') {
if a == -1 {
chars.next();
} else {

let a;
let mut b_sign = 0;
let mut token = *parser.parse::<Token![Any]>()?;
if matches!(token.char(), Some('+')) {
token = *parser.parse_with::<Token![Any]>(Include::Whitespace)?;
}
if !matches!(token.kind(), Kind::Number | Kind::Dimension | Kind::Ident) {
Err(diagnostics::Unexpected(token, token.span()))?
}
if token.is_float() {
Err(diagnostics::ExpectedInt(parser.parse_number(token), token.span()))?
}
match parser.parse_atom(token) {
atom!("-n") | atom!("-N") => {
if token.is_int() {
Err(diagnostics::Unexpected(token, token.span()))?
}
a = -1;
}
if !matches!(chars.next(), Some('n') | Some('N')) {
Err(diagnostics::UnexpectedIdent(parser.parse_atom(token), token.span()))?
atom!("n") | atom!("N") => {
a = if token.is_int() { parser.parse_number(token) as i32 } else { 1 };
}
if let Ok(i) = chars.as_str().parse::<i32>() {
Some(i)
} else if chars.as_str() != "" {
Err(diagnostics::UnexpectedIdent(parser.parse_atom(token), token.span()))?
} else {
None
atom!("n-") | atom!("N-") => {
b_sign = -1;
a = if token.is_int() { parser.parse_number(token) as i32 } else { 1 };
}
} else {
None
};
if let Some(token) = parser.peek::<Token![Number]>() {
if b.is_some() || token.is_float() || (!token.has_sign() || b_sign == 0) {
Err(diagnostics::ExpectedInt(parser.parse_number(token), token.span()))?
}
parser.hop(token);
if b_sign == 0 {
b_sign = 1
}
let i = parser.parse_number(token);
return Ok(Self(a, (i as i32) * b_sign));
}
if let Some(token) = parser.peek::<Token![Delim]>() {
if b.is_none() {
let char = token.char().unwrap();
if char == '-' {
b_sign = -1;
} else if char == '+' {
b_sign = 1;
anb => {
let mut chars = anb.chars();
let mut c = chars.next();
a = if token.is_int() {
parser.parse_number(token) as i32
} else if matches!(c, Some('-')) {
c = chars.next();
-1
} else {
1
};
if !matches!(c, Some('n') | Some('N')) {
Err(diagnostics::Unexpected(token, token.span()))?
}
if let Ok(b) = chars.as_str().parse::<i32>() {
return Ok(Self(a, b));
} else if !chars.as_str().is_empty() {
Err(diagnostics::Unexpected(token, token.span()))?
}
}
let num_token = *parser.parse::<Token![Number]>()?;
if num_token.is_float() || num_token.has_sign() {
Err(diagnostics::ExpectedInt(parser.parse_number(num_token), num_token.span()))?
}

if b_sign == 0 {
if let Some(token) = parser.peek::<Token![+]>() {
b_sign = 1;
parser.hop(token);
} else if let Some(token) = parser.peek::<Token![-]>() {
b_sign = -1;
parser.hop(token);
}
let i = parser.parse_number(token);
return Ok(Self(a, (i as i32) * b_sign));
}
Ok(Self(a, b.unwrap_or(0)))

let b = if let Some(token) = parser.peek::<Token![Number]>() {
if token.is_float() {
Err(diagnostics::ExpectedInt(parser.parse_number(token), token.span()))?
}
if token.has_sign() && b_sign != 0 {
Err(diagnostics::ExpectedUnsigned(parser.parse_number(token), token.span()))?
}
if b_sign == 0 {
b_sign = 1;
}
let i = parser.parse_number(token);
parser.hop(token);
(i.abs() as i32) * b_sign
} else {
0
};
Ok(Self(a, b))
}
}

Expand Down Expand Up @@ -159,9 +134,12 @@ mod tests {
#[test]
fn test_writes() {
assert_parse!(Nth, "odd");
assert_parse!(Nth, "ODD", "odd");
assert_parse!(Nth, "eVeN", "even");
assert_parse!(Nth, "5");
assert_parse!(Nth, "n");
assert_parse!(Nth, "+n", "n");
assert_parse!(Nth, "+N", "n");
assert_parse!(Nth, "-n");
assert_parse!(Nth, "+5", "5");
assert_parse!(Nth, "5n");
Expand All @@ -172,6 +150,7 @@ mod tests {
assert_parse!(Nth, "+n-4", "n-4");
assert_parse!(Nth, "+n+4", "n+4");
assert_parse!(Nth, "+n-123456789", "n-123456789");
assert_parse!(Nth, "2n", "even");
assert_parse!(Nth, "2n+1", "odd");
assert_parse!(Nth, "+2n+1", "odd");
assert_parse!(Nth, "-2n+1");
Expand Down
6 changes: 1 addition & 5 deletions crates/hdx_lexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,7 @@ impl<'a> Lexer<'a> {
return unit.to_atom();
}
}
let atom = self.parse_atom(token, allocator);
if !token.is_lower_case() {
return atom.to_ascii_lowercase();
}
atom
Atom::from(self.parse_str(token, allocator).to_ascii_lowercase())
}

#[inline]
Expand Down

0 comments on commit 51e294a

Please sign in to comment.