rpg_chat_command_parser/
parser.rs1use pest::Parser;
22use std::collections::HashMap;
23
24use crate::CommandError;
25#[derive(pest_derive::Parser)]
27#[grammar = "grammar.pest"] struct CommandParser;
29#[derive(Debug, PartialEq)]
31pub struct ParsedCommand {
32 pub verb: String,
34 pub target: Option<String>,
36 pub flags: HashMap<String, String>,
38}
39pub fn parse_command(input: &str) -> Result<ParsedCommand, CommandError> {
52 let parsed = CommandParser::parse(Rule::command, input)
53 .map_err(|e| {
54 println!("Debug: Parsing failed with error: {:?}", e);
55 CommandError::InvalidSyntax
56 })?
57 .next()
58 .ok_or_else(|| {
59 println!("Debug: No top-level rule matched");
60 CommandError::InvalidSyntax
61 })?
62 .into_inner();
63
64 let mut verb = String::new();
65 let mut target = None;
66 let mut flags = HashMap::new();
67
68 for pair in parsed {
69 println!(
70 "Debug: Top-level Pair = {:?}, Rule = {:?}",
71 pair.as_str(),
72 pair.as_rule()
73 );
74 match pair.as_rule() {
75 Rule::verb => verb = pair.as_str().to_string(),
76 Rule::target => target = Some(pair.as_str().to_string()),
77 Rule::flag => {
78 println!(
79 "Debug: Pair = {:?}, Rule = {:?}",
80 pair.as_str(),
81 pair.as_rule()
82 );
83 let mut inner = pair.into_inner(); let key = inner
86 .next()
87 .ok_or(CommandError::MissingFlagKey)? .as_str()
89 .to_string();
90 println!("Debug: Parsed key = {:?}", key);
91
92 if key.is_empty() || key.starts_with("=") || key.contains("--") {
94 println!("Debug: Invalid key detected = {:?}", key);
95 return Err(CommandError::MissingFlagKey);
96 }
97
98 let value_pair = inner.next().ok_or(CommandError::MissingFlagValue)?; let value = value_pair.as_str().to_string();
100
101 if value.is_empty() {
102 return Err(CommandError::MissingFlagValue);
103 }
104
105 println!("Debug: Parsed value = {:?}", value);
106 println!("Debug: Parsed key = {:?}, value = {:?}", key, value);
107 flags.insert(key, value);
108 }
109 Rule::bad_flag => {
110 println!("Debug: Malformed flag detected = {:?}", pair.as_str());
111 return Err(CommandError::InvalidSyntax);
112 }
113 _ => {}
114 }
115 }
116
117 if verb.is_empty() {
118 return Err(CommandError::MissingVerb);
119 }
120
121 Ok(ParsedCommand {
122 verb,
123 target,
124 flags,
125 })
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_missing_verb() {
134 let input = "--power=high"; let result = parse_command(input);
136 assert!(matches!(result, Err(CommandError::InvalidSyntax))); }
138
139 #[test]
140 fn test_missing_flag_key() {
141 let input = "/cast fireball --=high"; let result = parse_command(input);
143 assert!(matches!(result, Err(CommandError::MissingFlagKey)));
144 }
145
146 #[test]
147 fn test_invalid_flag_key() {
148 let input = "/cast fireball --==high"; let result = parse_command(input);
150 assert!(matches!(result, Err(CommandError::MissingFlagKey)));
151 }
152
153 #[test]
154 fn test_missing_flag_value() {
155 let input = "/cast fireball --power="; let result = parse_command(input);
157 assert!(matches!(result, Err(CommandError::MissingFlagValue)));
158 }
159
160 #[test]
161 fn test_valid_command() {
162 let input = "/cast fireball --power=high";
163 let result = parse_command(input).unwrap();
164 assert_eq!(result.verb, "cast");
165 assert_eq!(result.target, Some("fireball".to_string()));
166 assert_eq!(result.flags.get("power"), Some(&"high".to_string()));
167 }
168}