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