xiv_emote_parser/log_message/ast/
parser.rs1use super::types::*;
2use crate::log_message::parser::{LogMessageParser, Rule};
3
4use pest_consume::{match_nodes, Error};
5use std::str::FromStr;
6
7type Result<T> = std::result::Result<T, Error<Rule>>;
8type Node<'i> = pest_consume::Node<'i, Rule, ()>;
9
10#[pest_consume::parser]
11impl LogMessageParser {
12 #[allow(dead_code)]
13 fn EOI(_input: Node) -> Result<()> {
14 Ok(())
15 }
16
17 fn text(input: Node) -> Result<String> {
18 Ok(input.as_str().to_string())
19 }
20
21 fn tag_name(input: Node) -> Result<TagName> {
22 TagName::from_str(input.as_str()).map_err(|e| input.error(e))
23 }
24
25 fn func_name(input: Node) -> Result<FuncName> {
26 FuncName::from_str(input.as_str()).map_err(|e| input.error(e))
27 }
28
29 fn param_num(input: Node) -> Result<u32> {
30 input.as_str().parse().map_err(|e| input.error(e))
31 }
32
33 fn param_obj(input: Node) -> Result<Obj> {
34 Obj::from_str(input.as_str()).map_err(|e| input.error(e))
35 }
36
37 fn open_tag(input: Node) -> Result<Tag> {
38 Ok(match_nodes!(input.into_children();
39 [tag_name(name), param(params)..] => Tag { name, params: params.collect() }
40 ))
41 }
42
43 fn auto_closing_tag(input: Node) -> Result<Tag> {
44 Ok(match_nodes!(input.into_children();
45 [tag_name(name), param(params)..] => Tag { name, params: params.collect() }
46 ))
47 }
48
49 fn close_tag(input: Node) -> Result<TagName> {
50 Ok(match_nodes!(input.into_children();
51 [tag_name(name)] => name
52 ))
53 }
54
55 fn if_else_then_content(input: Node) -> Result<IfElseThen> {
56 Ok(match_nodes!(input.into_children();
57 [function(fun)] => IfElseThen::Function(fun),
58 [element(ele)] => IfElseThen::Element(ele),
59 [text(text)] => IfElseThen::Text(text),
60 ))
61 }
62
63 fn if_else_then(input: Node) -> Result<Vec<IfElseThen>> {
64 Ok(match_nodes!(input.into_children();
65 [if_else_then_content(content)..] => content.collect()
66 ))
67 }
68
69 fn if_param(input: Node) -> Result<IfParam> {
70 Ok(match_nodes!(input.into_children();
71 [function(fun)] => IfParam::Function(fun),
72 [auto_closing_tag(tag)] => IfParam::Tag(tag)
73 ))
74 }
75
76 fn if_else_element(input: Node) -> Result<Box<IfElse>> {
77 Ok(match_nodes!(input.into_children();
78 [if_param(if_cond), if_else_then(if_then), if_else_then(else_then)] =>
79 Box::new(IfElse { if_cond, if_then, else_then })
80 ))
81 }
82
83 fn element(input: Node) -> Result<Element> {
84 let nonmatch_err = Err(input.error("open and close tags do not match"));
86
87 Ok(match_nodes!(input.into_children();
88 [if_else_element(if_else)] => Element::IfElse(if_else),
89 [open_tag(tag), text(mut text).., close_tag(close_tag)] => if tag.name == close_tag {
90 Element::Tag(tag, text.next())
91 } else {
92 return nonmatch_err;
93 },
94 [auto_closing_tag(tag)] => Element::Tag(tag, None)
95 ))
96 }
97
98 fn function(input: Node) -> Result<Function> {
99 Ok(match_nodes!(input.into_children();
100 [func_name(name), param(params)..] => Function { name, params: params.collect() }
101 ))
102 }
103
104 fn param(input: Node) -> Result<Param> {
105 Ok(match_nodes!(input.into_children();
106 [element(element)] => Param::Element(element),
107 [param_num(num)] => Param::Num(num),
108 [param_obj(obj)] => Param::Obj(obj),
109 [function(func)] => Param::Function(func)
110 ))
111 }
112
113 fn message_part(input: Node) -> Result<MessagePart> {
114 Ok(match_nodes!(input.into_children();
115 [text(text)] => MessagePart::Text(text),
116 [element(element)] => MessagePart::Element(element)
117 ))
118 }
119
120 pub fn message(input: Node) -> Result<Message> {
121 Ok(match_nodes!(input.into_children();
122 [message_part(parts).., _] => Message(parts.collect())
123 ))
124 }
125}