Hone logo
Hone
Problems

Implementing a Simple syn Parser for Attribute-Like Structures

This challenge focuses on building a rudimentary parser using the syn crate in Rust. You'll be parsing a simplified version of Rust attributes, specifically focusing on identifying a name and a set of key-value pairs within the attribute. This exercise will help you understand how syn works and how to extract structured data from Rust code snippets.

Problem Description

You are tasked with creating a parser that can extract information from a simplified Rust attribute-like structure. The structure will consist of an identifier (the attribute name) followed by a block containing key-value pairs. Each key-value pair will be represented as key: value. The parser should identify the attribute name and collect all the key-value pairs into a suitable data structure.

What needs to be achieved:

  1. Parse a string representing the attribute-like structure.
  2. Identify the attribute name (an identifier).
  3. Extract all key-value pairs within the block.
  4. Represent the extracted data in a Rust struct.

Key Requirements:

  • Use the syn crate for parsing.
  • Handle potential parsing errors gracefully.
  • The parser should be able to handle empty key-value pairs (e.g., key:).
  • The parser should be able to handle multiple key-value pairs.
  • The parser should not attempt to parse complex Rust expressions within the values. Values should be treated as simple strings.

Expected Behavior:

The parser should return a Result containing either a ParsedAttribute struct (on success) or an error message (on failure). The ParsedAttribute struct should contain the attribute name (as a String) and a vector of key-value pairs, where each key-value pair is a tuple of (String, String).

Edge Cases to Consider:

  • Empty input string.
  • Invalid attribute name (e.g., starting with a number).
  • Missing colon in a key-value pair.
  • Unexpected tokens within the block.
  • Whitespace variations around the colon.

Examples

Example 1:

Input: "#[my_attribute key1:value1, key2:value2]"
Output: ParsedAttribute { name: "my_attribute", pairs: [("key1", "value1"), ("key2", "value2")] }
Explanation: The parser correctly identifies "my_attribute" as the attribute name and extracts the two key-value pairs.

Example 2:

Input: "#[another_attribute key1:, key2:value2]"
Output: ParsedAttribute { name: "another_attribute", pairs: [("key1", ""), ("key2", "value2")] }
Explanation: The parser handles the empty value for "key1" correctly.

Example 3:

Input: "#[invalid_attribute key1:value1,]"
Output: Error: Unexpected token ',' at line 1, column 25.
Explanation: The parser detects the trailing comma as an error.

Example 4:

Input: "#[attribute_with_spaces key1 : value1, key2:value2]"
Output: ParsedAttribute { name: "attribute_with_spaces", pairs: [("key1", "value1"), ("key2", "value2")] }
Explanation: The parser handles spaces around the colon.

Constraints

  • Input Length: The input string should not exceed 256 characters.
  • Input Format: The input string must start with "#[" and end with "]".
  • Key-Value Pair Format: Key-value pairs must be separated by commas. Keys and values should be simple strings without complex Rust expressions.
  • Performance: The parsing process should complete within 100ms for valid inputs. While not a primary focus, avoid excessively inefficient parsing strategies.

Notes

  • You'll need to add syn = { version = "1.0", features = ["full"] } to your Cargo.toml file.
  • Consider using syn::parse_macro_input to parse the input string.
  • You can define a custom derive(Debug) for your ParsedAttribute struct to easily print the parsed data.
  • Error handling is crucial. Provide informative error messages to help users understand what went wrong.
  • Focus on parsing the core structure. Don't worry about handling all possible Rust attribute features (e.g., meta items, tokens). Keep it simple and focused on the specified requirements.
  • Think about how to handle whitespace effectively. syn provides tools for ignoring whitespace.
  • Consider using syn::Error to create custom error messages.
Loading editor...
rust