spellcasting_parser/
lib.rs

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}