1use super::{BasicParseError, Parser, Token};
6
7pub fn parse_nth(input: &mut Parser) -> Result<(i32, i32), BasicParseError> {
12 match *input.next()? {
13 Token::Number {
14 int_value: Some(b), ..
15 } => Ok((0, b)),
16 Token::Dimension {
17 int_value: Some(a),
18 ref unit,
19 ..
20 } => {
21 match_ignore_ascii_case! {
22 unit,
23 "n" => parse_b(input, a),
24 "n-" => parse_signless_b(input, a, -1),
25 _ => match parse_n_dash_digits(unit) {
26 Ok(b) => Ok((a, b)),
27 Err(()) => {
28 Err(BasicParseError::unexpected_token())
29 }
30 }
31 }
32 }
33 Token::Ident(ref value) => {
34 match_ignore_ascii_case! { value,
35 "even" => Ok((2, 0)),
36 "odd" => Ok((2, 1)),
37 "n" => parse_b(input, 1),
38 "-n" => parse_b(input, -1),
39 "n-" => parse_signless_b(input, 1, -1),
40 "-n-" => parse_signless_b(input, -1, -1),
41 _ => {
42 let (slice, a) = if let Some(stripped) = value.strip_prefix('-') {
43 (stripped, -1)
44 } else {
45 (&**value, 1)
46 };
47 match parse_n_dash_digits(slice) {
48 Ok(b) => Ok((a, b)),
49 Err(()) => {
50 Err(BasicParseError::unexpected_token())
51 }
52 }
53 }
54 }
55 }
56 Token::Delim('+') => match *input.next_including_whitespace()? {
57 Token::Ident(ref value) => {
58 match_ignore_ascii_case! { value,
59 "n" => parse_b(input, 1),
60 "n-" => parse_signless_b(input, 1, -1),
61 _ => match parse_n_dash_digits(value) {
62 Ok(b) => Ok((1, b)),
63 Err(()) => {
64 Err(BasicParseError::unexpected_token())
65 }
66 }
67 }
68 }
69 _ => Err(BasicParseError::unexpected_token()),
70 },
71 _ => Err(BasicParseError::unexpected_token()),
72 }
73}
74
75fn parse_b(input: &mut Parser, a: i32) -> Result<(i32, i32), BasicParseError> {
76 let start = input.state();
77 match input.next() {
78 Ok(&Token::Delim('+')) => parse_signless_b(input, a, 1),
79 Ok(&Token::Delim('-')) => parse_signless_b(input, a, -1),
80 Ok(&Token::Number {
81 has_sign: true,
82 int_value: Some(b),
83 ..
84 }) => Ok((a, b)),
85 _ => {
86 input.reset(&start);
87 Ok((a, 0))
88 }
89 }
90}
91
92fn parse_signless_b(
93 input: &mut Parser,
94 a: i32,
95 b_sign: i32,
96) -> Result<(i32, i32), BasicParseError> {
97 match input.next()? {
98 &Token::Number {
99 has_sign: false,
100 int_value: Some(b),
101 ..
102 } => Ok((a, b_sign * b)),
103 _ => Err(BasicParseError::unexpected_token()),
104 }
105}
106
107fn parse_n_dash_digits(string: &str) -> Result<i32, ()> {
108 let bytes = string.as_bytes();
109 if bytes.len() >= 3
110 && bytes[..2].eq_ignore_ascii_case(b"n-")
111 && bytes[2..].iter().all(|&c| c.is_ascii_digit())
112 {
113 Ok(parse_number_saturate(&string[1..]).unwrap()) } else {
115 Err(())
116 }
117}
118
119fn parse_number_saturate(string: &str) -> Result<i32, ()> {
120 let mut parser = Parser::new(string);
121 let int = if let Ok(&Token::Number {
122 int_value: Some(int),
123 ..
124 }) = parser.next_including_whitespace_and_comments()
125 {
126 int
127 } else {
128 return Err(());
129 };
130 if !parser.is_exhausted() {
131 return Err(());
132 }
133 Ok(int)
134}