### Rust: Basic Parser Setup and Token Iteration Source: https://context7.com/servo/rust-cssparser/llms.txt Demonstrates how to set up a CSS parser in Rust using rust-cssparser and iterate through its tokens. It shows basic token matching and how to include or exclude whitespace and comments during iteration. ```rust use cssparser::{Parser, ParserInput, Token}; // Create parser input from CSS string let css = "color: red; background: blue;"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); // Iterate through tokens (skips whitespace and comments) loop { match parser.next() { Ok(token) => { match token { Token::Ident(name) => println!("Identifier: {}", name), Token::Colon => println!("Colon"), Token::Semicolon => println!("Semicolon"), Token::Delim(c) => println!("Delimiter: {}", c), _ => println!("Token: {:?}", token), } } Err(_) => { // End of input or parse error break; } } } // Include whitespace in iteration let mut input2 = ParserInput::new("foo bar"); let mut parser2 = Parser::new(&mut input2); while let Ok(token) = parser2.next_including_whitespace() { println!("{:?}", token); } // Output: Ident("foo"), WhiteSpace(" "), Ident("bar") // Include both whitespace and comments let mut input3 = ParserInput::new("foo /* comment */ bar"); let mut parser3 = Parser::new(&mut input3); while let Ok(token) = parser3.next_including_whitespace_and_comments() { println!("{:?}", token); } // Output: Ident("foo"), WhiteSpace(" "), Comment(" comment "), WhiteSpace(" "), Ident("bar") ``` -------------------------------- ### Rust: Parsing Comma-Separated Lists Source: https://context7.com/servo/rust-cssparser/llms.txt Illustrates parsing comma-separated lists of values in CSS using the `parse_comma_separated` method from the `cssparser` crate. Examples include parsing font family names (identifiers or strings) and numerical lengths with units. Dependencies include the `cssparser` crate. ```rust use cssparser::{Parser, ParserInput, ParseError}; fn parse_font_family(input: &mut Parser) -> Result, ParseError<()>> { input.parse_comma_separated(|input| { // Each font family can be a quoted string or an identifier let family = input.expect_ident_or_string()?; Ok(family.to_string()) }) } // Example usage let css = "Arial, 'Times New Roman', sans-serif"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); match parse_font_family(&mut parser) { Ok(families) => { println!("Font families:"); for family in families { println!(" - {}", family); } } Err(e) => println!("Parse error: {:?}", e), } // Output: // Font families: // - Arial // - Times New Roman // - sans-serif // Parsing multiple values with custom parser fn parse_lengths(input: &mut Parser) -> Result, ParseError<()>> { input.parse_comma_separated(|input| { let token = input.next()?; match token { cssparser::Token::Dimension { value, unit, .. } if unit == "px" => Ok(*value), cssparser::Token::Number { value, .. } => Ok(*value), _ => Err(input.new_custom_error(())), } }) } let css = "10px, 20, 30px"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); let lengths = parse_lengths(&mut parser).unwrap(); println!("Lengths: {:?}", lengths); // Lengths: [10.0, 20.0, 30.0] ``` -------------------------------- ### CSS urange Syntax Testing Source: https://github.com/servo/rust-cssparser/blob/main/src/css-parsing-tests/README.rst Tests the urange syntax defined in CSS Syntax Level 3. The input is a JSON string representing Unicode, and the output is either null for invalid syntax or an array of two integers [start, end]. ```json { "tests": [ { "input": "U+2000-U+200A", "output": [8192, 8192+10] }, { "input": "U+0020", "output": [32, 32] }, { "input": "invalid", "output": null } ] } ``` -------------------------------- ### Serialize CSS Tokens and Identifiers in Rust Source: https://context7.com/servo/rust-cssparser/llms.txt Demonstrates serializing various CSS tokens, identifiers, and strings back into their CSS string representation using the cssparser library's `ToCss` trait. It covers basic tokens like `color` and `:`, escaped identifiers with special characters or spaces, and properly quoted strings. The example also shows how to implement `ToCss` for custom structs, like a `Color` struct, to serialize them into CSS values (e.g., `rgb(...)`). ```rust use cssparser::{Parser, ParserInput, Token, ToCss, serialize_identifier, serialize_string}; use std::fmt::Write; // Serialize individual tokens fn serialize_tokens(css: &str) { let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); while let Ok(token) = parser.next_including_whitespace() { let serialized = token.to_css_string(); println!("Token: {:?} => {}", token, serialized); } } serialize_tokens("color: red"); // Output: // Token: Ident("color") => color // Token: Colon => : // Token: WhiteSpace(" ") => // Token: Ident("red") => red // Serialize identifiers with proper escaping let identifiers = vec!["simple", "with-dash", "123start", "with space"]; for ident in identifiers { let mut output = String::new(); serialize_identifier(ident, &mut output).unwrap(); println!("{} => {}", ident, output); } // Output: // simple => simple // with-dash => with-dash // 123start => \31 23start // with space => with\ space // Serialize strings with proper escaping let strings = vec!["hello", "with\"quotes\"", "line\nbreak"]; for s in strings { let mut output = String::new(); serialize_string(s, &mut output).unwrap(); println!("{:?}" => {}", s, output); } // Output: // "hello" => "hello" // "with\"quotes\"" => "with\"quotes\"" // "line\nbreak" => "line\nbreak" // Custom struct implementing ToCss #[derive(Debug)] struct Color { r: u8, g: u8, b: u8, } impl ToCss for Color { fn to_css(&self, dest: &mut W) -> std::fmt::Result where W: Write { write!(dest, "rgb({}, {}, {})", self.r, self.g, self.b) } } let color = Color { r: 255, g: 128, b: 0 }; println!("Color CSS: {}", color.to_css_string()); // Output: Color CSS: rgb(255, 128, 0) ``` -------------------------------- ### Implement Custom CSS Parse Error Handling in Rust Source: https://context7.com/servo/rust-cssparser/llms.txt Illustrates how to define and use custom error types with `cssparser` in Rust. This example shows a function that parses a color, returning a `CustomError` enum if the color is not one of the allowed values, and demonstrates how to handle these custom errors during parsing. ```rust // Custom error type #[derive(Debug)] enum CustomError { InvalidColor, InvalidUnit, } fn parse_color_with_custom_error(input: &mut Parser) -> Result> { let color = input.expect_ident()?; // Validate color if !["red", "green", "blue", "black", "white"].contains(&color.as_ref()) { return Err(input.new_custom_error(CustomError::InvalidColor)); } Ok(color.to_string()) } let css = "purple"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); match parse_color_with_custom_error(&mut parser) { Ok(color) => println!("Valid color: {}", color), Err(e) => println!("Error: {:?} at line {}, col {}", e.kind, e.location.line, e.location.column), } // Output: Error: Custom(InvalidColor) at line 1, col 1 ``` -------------------------------- ### Parse CSS Unicode Ranges in Rust Source: https://context7.com/servo/rust-cssparser/llms.txt Parses Unicode range values, commonly used in CSS @font-face descriptors, using the cssparser library. It demonstrates how to parse single ranges like 'U+0025-00FF' and multiple comma-separated ranges. The function returns a vector of UnicodeRange structs, each containing start and end code points. It also shows how to extract these ranges from a CSS string. ```rust use cssparser::{Parser, ParserInput, UnicodeRange}; fn parse_unicode_ranges(css: &str) -> Result, Box> { let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); let ranges = parser.parse_comma_separated(|parser| { UnicodeRange::parse(parser).map_err(|e| e.into()) })?; Ok(ranges) } // Parse single range let css = "U+0025-00FF"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); let range = UnicodeRange::parse(&mut parser).unwrap(); println!("Range: U+{:04X}-U+{:04X}", range.start, range.end); // Output: Range: U+0025-U+00FF // Parse multiple ranges let css = "U+0025-00FF, U+4E00-9FFF, U+30??"; match parse_unicode_ranges(css) { Ok(ranges) => { for range in ranges { println!("U+{:04X}-U+{:04X} ({} characters)", range.start, range.end, range.end - range.start + 1); } } Err(e) => println!("Error: {}", e), } // Output: // U+0025-U+00FF (219 characters) // U+4E00-U+9FFF (20992 characters) // U+3000-U+30FF (256 characters) // Using in @font-face context let css = r#"@font-face { font-family: 'MyFont'; unicode-range: U+0025-00FF, U+4E00-9FFF; } "#; ``` -------------------------------- ### Rust: Try-Parse with Rollback for Alternatives Source: https://context7.com/servo/rust-cssparser/llms.txt Demonstrates the try-parse pattern for backtracking when parsing alternative CSS values like 'none', 'url()', or color names. It uses a closure to attempt parsing and rolls back if it fails, allowing subsequent alternatives to be tried. Dependencies include the `cssparser` crate. ```rust use cssparser::{Parser, ParserInput, ParseError}; #[derive(Debug)] enum BackgroundValue { None, Color(String), Url(String), } fn parse_background(input: &mut Parser) -> Result> { // Try parsing "none" keyword if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() { return Ok(BackgroundValue::None); } // Try parsing a URL if let Ok(url) = input.try_parse(|input| input.expect_url()) { return Ok(BackgroundValue::Url(url.to_string())); } // Try parsing a color name if let Ok(color) = input.try_parse(|input| input.expect_ident()) { return Ok(BackgroundValue::Color(color.to_string())); } // Nothing matched Err(input.new_custom_error(())) } // Examples let test_cases = vec![ "none", "url(image.png)", "red", ]; for css in test_cases { let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); match parse_background(&mut parser) { Ok(bg) => println!("{:?}", bg), Err(_) => println!("Failed to parse: {}", css), } } // Output: // None // Url("image.png") // Color("red") ``` -------------------------------- ### Rust: Parsing Nested Blocks and Functions Source: https://context7.com/servo/rust-cssparser/llms.txt Demonstrates parsing nested blocks (like `rgb(...)` or `{ ... }`) and function calls using the `cssparser` crate. It shows how to expect specific function names and parse content within nested structures, including handling expected tokens like integers and commas. Dependencies include the `cssparser` crate. ```rust use cssparser::{Parser, ParserInput, Token, ParseError}; fn parse_rgb_function(input: &mut Parser) -> Result<(u8, u8, u8), ParseError<()>> { // Expect function token with name "rgb" input.expect_function_matching("rgb")?; // Parse the contents inside rgb(...) input.parse_nested_block(|input| { let r = input.expect_integer()?; input.expect_comma()?; let g = input.expect_integer()?; input.expect_comma()?; let b = input.expect_integer()?; Ok((r as u8, g as u8, b as u8)) }) } // Example usage let css = "rgb(255, 128, 0)"; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); match parse_rgb_function(&mut parser) { Ok((r, g, b)) => println!("RGB: ({}, {}, {})", r, g, b), Err(e) => println!("Parse error: {:?}", e), } // Output: RGB: (255, 128, 0) // Parsing generic block contents fn parse_curly_block(input: &mut Parser) -> Result, ParseError<()>> { input.expect_curly_bracket_block()?; input.parse_nested_block(|input| { let mut values = Vec::new(); while !input.is_exhausted() { if let Ok(ident) = input.expect_ident() { values.push(ident.to_string()); } else { // Skip other tokens let _ = input.next(); } } Ok(values) }) } let css = "{ foo bar baz }" ; let mut input = ParserInput::new(css); let mut parser = Parser::new(&mut input); let values = parse_curly_block(&mut parser).unwrap(); println!("Block contents: {:?}", values); // Block contents: ["foo", "bar", "baz"] ``` -------------------------------- ### CSS Syntax AST Node Representation (JSON) Source: https://github.com/servo/rust-cssparser/blob/main/src/css-parsing-tests/README.rst Illustrates the JSON representation of Abstract Syntax Tree (AST) nodes generated by the CSS parser. This compact representation distinguishes between different CSS constructs and their values. ```json ["at-keyword", "import"] ``` ```json ["ident", "@import"] ``` ```json ["at-rule", "charset", [["string", "utf-8"]], null] ``` ```json ["qualified rule", [["ident", "body"]], [["declaration", "color", [["ident", "red"]], false]]] ``` ```json ["declaration", "margin", [["dimension", "10px", 10, "number", "px"]], true] ``` ```json ["ident", "color"] ``` ```json ["hash", "main", "id"] ``` ```json ["string", "Hello World"] ``` ```json ["bad-string"] ``` ```json ["url", "http://example.com"] ``` ```json ["bad-url"] ``` ```json "," ``` ```json ["number", "10", 10, "integer"] ``` ```json ["percentage", "50%", 50, "number"] ``` ```json ["dimension", "2em", 2, "number", "em"] ``` ```json "~=" ``` ```json "^=" ``` ```json "*=" ``` ```json " " ``` ```json "