keyvalues_parser/text/parse/
raw.rs

1use super::*;
2
3pub type PestError = pest::error::Error<Rule>;
4type BoxedState<'a> = Box<pest::ParserState<'a, Rule>>;
5type ParseResult<'a> = pest::ParseResult<BoxedState<'a>>;
6
7common_parsing!(pest_parse, Rule, false);
8
9/// Attempts to parse VDF text to a [`Vdf`]
10#[deprecated(
11    since = "0.2.3",
12    note = "Please use `Parser::new().literal_special_chars(true).parse()` instead"
13)]
14pub fn parse(s: &str) -> Result<PartialVdf<'_>> {
15    parse_(s)
16}
17
18#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
19#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
20pub enum Rule {
21    ///End-of-input
22    EOI,
23    WHITESPACE,
24    COMMENT,
25    vdf,
26    base_macro,
27    quoted_raw_string,
28    pairs,
29    pair,
30    key,
31    value,
32    obj,
33    quoted_string,
34    quoted_inner,
35    unquoted_string,
36    unquoted_char,
37}
38
39mod rules {
40    #![allow(non_snake_case)]
41
42    use super::{any, skip, soi, whitespace, BoxedState, ParseResult, Rule};
43
44    use pest::Atomicity;
45
46    #[inline]
47    pub fn vdf(s: BoxedState<'_>) -> ParseResult<'_> {
48        s.sequence(|s| {
49            soi(s)
50                .and_then(skip)
51                .and_then(|s| {
52                    s.sequence(|s| {
53                        s.optional(|s| {
54                            base_macro(s).and_then(|s| {
55                                s.repeat(|s| s.sequence(|s| skip(s).and_then(base_macro)))
56                            })
57                        })
58                    })
59                })
60                .and_then(skip)
61                .and_then(pair)
62                .and_then(skip)
63                .and_then(|s| s.optional(|s| s.match_string("\0")))
64                .and_then(skip)
65                .and_then(EOI)
66        })
67    }
68    pub fn base_macro(s: BoxedState<'_>) -> ParseResult<'_> {
69        s.rule(Rule::base_macro, |s| {
70            s.sequence(|s| {
71                s.match_string("#base")
72                    .and_then(skip)
73                    .and_then(|s| quoted_raw_string(s).or_else(unquoted_string))
74            })
75        })
76    }
77    #[inline]
78    pub fn quoted_raw_string(s: BoxedState<'_>) -> ParseResult<'_> {
79        s.atomic(Atomicity::CompoundAtomic, |s| {
80            s.rule(Rule::quoted_raw_string, |s| {
81                s.sequence(|s| {
82                    s.match_string("\"")
83                        .and_then(quoted_inner)
84                        .and_then(|s| s.match_string("\""))
85                })
86            })
87        })
88    }
89    #[inline]
90    pub fn pairs(s: BoxedState<'_>) -> ParseResult<'_> {
91        s.sequence(|s| {
92            s.optional(|s| {
93                pair(s).and_then(|s| s.repeat(|s| s.sequence(|s| skip(s).and_then(pair))))
94            })
95        })
96    }
97    #[inline]
98    pub fn pair(s: BoxedState<'_>) -> ParseResult<'_> {
99        s.rule(Rule::pair, |s| {
100            s.sequence(|s| key(s).and_then(skip).and_then(value))
101        })
102    }
103    #[inline]
104    pub fn key(s: BoxedState<'_>) -> ParseResult<'_> {
105        quoted_string(s).or_else(unquoted_string)
106    }
107    #[inline]
108    pub fn value(s: BoxedState<'_>) -> ParseResult<'_> {
109        quoted_string(s).or_else(obj).or_else(unquoted_string)
110    }
111    #[inline]
112    pub fn obj(s: BoxedState<'_>) -> ParseResult<'_> {
113        s.rule(Rule::obj, |s| {
114            s.sequence(|s| {
115                s.match_string("{")
116                    .and_then(skip)
117                    .and_then(pairs)
118                    .and_then(skip)
119                    .and_then(|s| s.match_string("}"))
120            })
121        })
122    }
123    #[inline]
124    pub fn quoted_string(s: BoxedState<'_>) -> ParseResult<'_> {
125        s.atomic(Atomicity::CompoundAtomic, |s| {
126            s.rule(Rule::quoted_string, |s| {
127                s.sequence(|s| {
128                    s.match_string("\"")
129                        .and_then(quoted_inner)
130                        .and_then(|s| s.match_string("\""))
131                })
132            })
133        })
134    }
135    #[inline]
136    pub fn quoted_inner(s: BoxedState<'_>) -> ParseResult<'_> {
137        s.rule(Rule::quoted_inner, |s| {
138            s.atomic(Atomicity::Atomic, |s| s.skip_until(&["\""]))
139        })
140    }
141    #[inline]
142    pub fn unquoted_string(s: BoxedState<'_>) -> ParseResult<'_> {
143        s.rule(Rule::unquoted_string, |s| {
144            s.atomic(Atomicity::Atomic, |s| {
145                s.sequence(|s| unquoted_char(s).and_then(|s| s.repeat(unquoted_char)))
146            })
147        })
148    }
149    #[inline]
150    pub fn unquoted_char(s: BoxedState<'_>) -> ParseResult<'_> {
151        s.rule(Rule::unquoted_char, |s| {
152            s.sequence(|s| {
153                s.lookahead(false, |s| {
154                    s.match_string("\"")
155                        .or_else(|s| s.match_string("{"))
156                        .or_else(|s| s.match_string("}"))
157                        .or_else(whitespace)
158                })
159                .and_then(skip)
160                .and_then(any)
161            })
162        })
163    }
164    pub fn EOI(s: BoxedState<'_>) -> ParseResult<'_> {
165        s.rule(Rule::EOI, |s| s.end_of_input())
166    }
167}
168
169pub fn pest_parse(input: &str) -> std::result::Result<pest::iterators::Pairs<'_, Rule>, PestError> {
170    pest::state(input, rules::vdf)
171}