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