1use anyhow::{anyhow, Result};
2use pest::iterators::{Pair, Pairs};
3use pest::Parser;
4use pest_derive::Parser;
5use std::fmt;
6
7#[derive(Parser)]
8#[grammar = "./grammar.pest"]
9pub struct Grammar;
10
11#[derive(Debug, PartialEq)]
12pub struct Spells {
13 pub spells: Vec<Spell>,
14}
15
16#[derive(Debug, PartialEq)]
17pub struct Spell {
18 pub invoke_word: String,
19 pub spell_type_params: SpellTypePart,
20 pub executable_params: Vec<ExecutablePart>,
21}
22
23#[derive(Debug, PartialEq)]
24pub struct SpellTypePart {
25 pub spell_type: String,
26 pub modifiers: Modifiers,
27}
28
29#[derive(Debug, PartialEq, Default)]
30pub struct Modifiers {
31 pub modifiers: Vec<Modifier>,
32}
33
34#[derive(Debug, PartialEq)]
35pub enum Modifier {
36 Adjective { value: String },
37 Repetition { value: u32 },
38 Condition { condition_type: String },
39 Duration { value: String },
40}
41
42#[derive(Debug, PartialEq)]
43pub struct ExecutablePart {
44 pub executable: Executable,
45 pub modifiers: Modifiers,
46}
47
48#[derive(Debug, PartialEq)]
49pub struct Executable {
50 pub value: String,
51}
52
53impl fmt::Display for Spells {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 writeln!(f, "Spells:")?;
56 for spell in &self.spells {
57 writeln!(f, "{}", spell)?;
58 }
59 Ok(())
60 }
61}
62
63impl fmt::Display for Spell {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(
66 f,
67 "Invoke: {}\nSpell Type: {}\nExecutable Params: {}\n",
68 self.invoke_word,
69 self.spell_type_params,
70 self.executable_params
71 .iter()
72 .map(|p| p.to_string())
73 .collect::<Vec<String>>()
74 .join(", ")
75 )
76 }
77}
78
79impl fmt::Display for SpellTypePart {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(
82 f,
83 "{} with modifiers: [{}]",
84 self.spell_type,
85 self.modifiers
86 .modifiers
87 .iter()
88 .map(|m| m.to_string())
89 .collect::<Vec<String>>()
90 .join(", ")
91 )
92 }
93}
94
95impl fmt::Display for Modifiers {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 if self.modifiers.is_empty() {
98 write!(f, "No modifiers")
99 } else {
100 write!(
101 f,
102 "{}",
103 self.modifiers
104 .iter()
105 .map(|m| m.to_string())
106 .collect::<Vec<String>>()
107 .join(", ")
108 )
109 }
110 }
111}
112
113impl fmt::Display for Modifier {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 match *self {
116 Modifier::Adjective { ref value } => write!(f, "Adjective: {}", value),
117 Modifier::Repetition { value } => write!(f, "Repetition: {}", value),
118 Modifier::Condition { ref condition_type } => {
119 write!(f, "Condition: {}", condition_type)
120 }
121 Modifier::Duration { ref value } => write!(f, "Duration: {}", value),
122 }
123 }
124}
125
126impl fmt::Display for ExecutablePart {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 write!(
129 f,
130 "{} with modifiers: [{}]",
131 self.executable.value,
132 self.modifiers
133 .modifiers
134 .iter()
135 .map(|m| m.to_string())
136 .collect::<Vec<String>>()
137 .join(", ")
138 )
139 }
140}
141
142impl fmt::Display for Executable {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(f, "Executable: {}", self.value)
145 }
146}
147
148pub fn raw_parse_string(input: &str) -> Result<Pairs<Rule>, anyhow::Error> {
149 let parsed_data = Grammar::parse(Rule::spells, input);
150
151 match parsed_data {
152 Ok(pairs) => Ok(pairs),
153 Err(e) => Err(anyhow::anyhow!("Error during parsing: {}", e)),
154 }
155}
156
157pub fn parse_string(input: &str) -> Result<Spells, anyhow::Error> {
158 let mut error_details = Vec::new();
159 let parsed_data = match raw_parse_string(input) {
160 Ok(data) => data,
161 Err(e) => {
162 error_details.push(format!("Raw parsing error: {}", e));
163 return Err(anyhow::anyhow!("Parsing failed with multiple errors")
164 .context(error_details.join(", ")));
165 }
166 };
167
168 match parse_to_structure(parsed_data) {
169 Ok(spells) => Ok(spells),
170 Err(e) => {
171 error_details.push(format!("Structure conversion error: {}", e));
172 Err(anyhow::anyhow!("Parsing failed with multiple errors")
173 .context(error_details.join(", ")))
174 }
175 }
176}
177
178pub fn parse_to_structure(pairs: Pairs<Rule>) -> Result<Spells, anyhow::Error> {
179 let mut spells = Vec::new();
180
181 for pair in pairs {
182 if pair.as_rule() == Rule::spell {
183 let spell = parse_spell(pair)?;
184 spells.push(spell);
185 }
186 }
187
188 Ok(Spells { spells })
189}
190
191fn parse_spell(pair: Pair<Rule>) -> Result<Spell, anyhow::Error> {
192 let mut invoke_word = String::new();
193 let mut spell_type_params = None;
194 let mut executable_params = Vec::new();
195
196 for inner_pair in pair.into_inner() {
197 match inner_pair.as_rule() {
198 Rule::invoke_word => invoke_word = inner_pair.as_str().to_string(),
199 Rule::spell_type_params => {
200 spell_type_params = Some(parse_spell_type_part(inner_pair)?);
201 }
202 Rule::executable_params => {
203 executable_params.push(parse_executable_part(inner_pair)?);
204 }
205 _ => {}
206 }
207 }
208
209 Ok(Spell {
210 invoke_word,
211 spell_type_params: spell_type_params.ok_or_else(|| anyhow!("Missing spell_type_params"))?,
212 executable_params,
213 })
214}
215
216fn parse_spell_type_part(pair: Pair<Rule>) -> Result<SpellTypePart, anyhow::Error> {
217 let mut spell_type = String::new();
218 let mut modifiers = Modifiers::default();
219
220 for inner_pair in pair.into_inner() {
221 match inner_pair.as_rule() {
222 Rule::spell_type => spell_type = inner_pair.as_str().to_string(),
223 Rule::modifiers => modifiers = parse_modifiers(inner_pair)?,
224 _ => {}
225 }
226 }
227
228 Ok(SpellTypePart {
229 spell_type,
230 modifiers,
231 })
232}
233
234fn parse_modifiers(pair: Pair<Rule>) -> Result<Modifiers, anyhow::Error> {
235 let mut modifiers = Vec::new();
236
237 for inner_pair in pair.into_inner() {
238 match inner_pair.as_rule() {
239 Rule::adjective => modifiers.push(Modifier::Adjective {
240 value: inner_pair.as_str().to_string(),
241 }),
242 Rule::condition => modifiers.push(Modifier::Condition {
243 condition_type: inner_pair.as_str().to_string(),
244 }),
245 Rule::repetition => modifiers.push(Modifier::Repetition {
246 value: parse_repetition(inner_pair)?,
247 }),
248 Rule::duration => modifiers.push(Modifier::Duration {
249 value: inner_pair.as_str().to_string(),
250 }),
251 _ => {}
252 }
253 }
254 Ok(Modifiers { modifiers })
255}
256
257fn parse_repetition(pair: Pair<Rule>) -> Result<u32> {
258 if let Some(inner_pair) = pair.into_inner().next() {
259 match inner_pair.as_rule() {
260 Rule::number => {
261 let value = inner_pair
262 .as_str()
263 .parse::<u32>()
264 .map_err(|e| anyhow!("Failed to parse number: {}", e))?;
265 return Ok(value);
266 }
267 _ => {
268 return Err(anyhow!(
269 "Unexpected rule inside repetition: {:?}",
270 inner_pair.as_rule()
271 ));
272 }
273 }
274 }
275 Err(anyhow!("No number found in repetition"))
276}
277
278fn parse_executable_part(pair: Pair<Rule>) -> Result<ExecutablePart, anyhow::Error> {
279 let mut executable = None;
280 let mut modifiers = Modifiers::default();
281
282 for inner_pair in pair.into_inner() {
283 match inner_pair.as_rule() {
284 Rule::executable => {
285 executable = Some(Executable {
286 value: inner_pair.as_str().to_string(),
287 });
288 }
289 Rule::modifiers => modifiers = parse_modifiers(inner_pair)?,
290 _ => {}
291 }
292 }
293
294 Ok(ExecutablePart {
295 executable: executable.ok_or_else(|| anyhow!("Missing executable"))?,
296 modifiers,
297 })
298}