keyvalues_parser/text/parse/
escaped.rs1use 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, true);
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 EOI,
14 WHITESPACE,
15 COMMENT,
16 vdf,
17 base_macro,
18 quoted_raw_string,
19 quoted_raw_inner,
20 pairs,
21 pair,
22 key,
23 value,
24 obj,
25 quoted_string,
26 quoted_inner,
27 char,
28 unquoted_string,
29 unquoted_char,
30}
31
32mod rules {
33 #![allow(non_snake_case)]
34
35 use super::{any, skip, soi, whitespace, BoxedState, ParseResult, Rule};
36
37 use pest::Atomicity;
38
39 #[inline]
40 pub fn vdf(s: BoxedState<'_>) -> ParseResult<'_> {
41 s.sequence(|s| {
42 soi(s)
43 .and_then(skip)
44 .and_then(|s| {
45 s.sequence(|s| {
46 s.optional(|s| {
47 base_macro(s).and_then(|s| {
48 s.repeat(|s| s.sequence(|s| skip(s).and_then(base_macro)))
49 })
50 })
51 })
52 })
53 .and_then(skip)
54 .and_then(pair)
55 .and_then(skip)
56 .and_then(|s| s.optional(|s| s.match_string("\0")))
57 .and_then(skip)
58 .and_then(EOI)
59 })
60 }
61 pub fn base_macro(s: BoxedState<'_>) -> ParseResult<'_> {
62 s.rule(Rule::base_macro, |s| {
63 s.sequence(|s| {
64 s.match_string("#base")
65 .and_then(skip)
66 .and_then(|s| quoted_raw_string(s).or_else(unquoted_string))
67 })
68 })
69 }
70 #[inline]
71 pub fn quoted_raw_string(s: BoxedState<'_>) -> ParseResult<'_> {
72 s.atomic(Atomicity::CompoundAtomic, |s| {
73 s.rule(Rule::quoted_raw_string, |s| {
74 s.sequence(|s| {
75 s.match_string("\"")
76 .and_then(quoted_raw_inner)
77 .and_then(|s| s.match_string("\""))
78 })
79 })
80 })
81 }
82 #[inline]
83 pub fn quoted_raw_inner(s: BoxedState<'_>) -> ParseResult<'_> {
84 s.rule(Rule::quoted_raw_inner, |s| {
85 s.atomic(Atomicity::Atomic, |s| s.skip_until(&["\""]))
86 })
87 }
88 #[inline]
89 pub fn pairs(s: BoxedState<'_>) -> ParseResult<'_> {
90 s.sequence(|s| {
91 s.optional(|s| {
92 pair(s).and_then(|s| s.repeat(|s| s.sequence(|s| skip(s).and_then(pair))))
93 })
94 })
95 }
96 #[inline]
97 pub fn pair(s: BoxedState<'_>) -> ParseResult<'_> {
98 s.rule(Rule::pair, |s| {
99 s.sequence(|s| key(s).and_then(skip).and_then(value))
100 })
101 }
102 #[inline]
103 pub fn key(s: BoxedState<'_>) -> ParseResult<'_> {
104 quoted_string(s).or_else(unquoted_string)
105 }
106 #[inline]
107 pub fn value(s: BoxedState<'_>) -> ParseResult<'_> {
108 quoted_string(s).or_else(obj).or_else(unquoted_string)
109 }
110 #[inline]
111 pub fn obj(s: BoxedState<'_>) -> ParseResult<'_> {
112 s.rule(Rule::obj, |s| {
113 s.sequence(|s| {
114 s.match_string("{")
115 .and_then(skip)
116 .and_then(pairs)
117 .and_then(skip)
118 .and_then(|s| s.match_string("}"))
119 })
120 })
121 }
122 #[inline]
123 pub fn quoted_string(s: BoxedState<'_>) -> ParseResult<'_> {
124 s.atomic(Atomicity::CompoundAtomic, |s| {
125 s.rule(Rule::quoted_string, |s| {
126 s.sequence(|s| {
127 s.match_string("\"")
128 .and_then(quoted_inner)
129 .and_then(|s| s.match_string("\""))
130 })
131 })
132 })
133 }
134 #[inline]
135 pub fn quoted_inner(s: BoxedState<'_>) -> ParseResult<'_> {
136 s.rule(Rule::quoted_inner, |s| {
137 s.atomic(Atomicity::Atomic, |s| s.repeat(char))
138 })
139 }
140 #[inline]
141 pub fn char(s: BoxedState<'_>) -> ParseResult<'_> {
142 s.rule(Rule::char, |s| {
143 s.sequence(|s| {
144 s.lookahead(false, |s| {
145 s.match_string("\"").or_else(|s| s.match_string("\\"))
146 })
147 .and_then(skip)
148 .and_then(any)
149 })
150 .or_else(|s| {
151 s.sequence(|s| {
152 s.match_string("\\").and_then(skip).and_then(|s| {
153 s.match_string("\"")
154 .or_else(|s| s.match_string("\\"))
155 .or_else(|s| s.match_string("n"))
156 .or_else(|s| s.match_string("r"))
157 .or_else(|s| s.match_string("t"))
158 })
159 })
160 })
161 })
162 }
163 #[inline]
164 pub fn unquoted_string(s: BoxedState<'_>) -> ParseResult<'_> {
165 s.rule(Rule::unquoted_string, |s| {
166 s.atomic(Atomicity::Atomic, |s| {
167 s.sequence(|s| unquoted_char(s).and_then(|s| s.repeat(unquoted_char)))
168 })
169 })
170 }
171 #[inline]
172 pub fn unquoted_char(s: BoxedState<'_>) -> ParseResult<'_> {
173 s.rule(Rule::unquoted_char, |s| {
174 s.sequence(|s| {
175 s.lookahead(false, |s| {
176 s.match_string("\"")
177 .or_else(|s| s.match_string("{"))
178 .or_else(|s| s.match_string("}"))
179 .or_else(whitespace)
180 })
181 .and_then(skip)
182 .and_then(any)
183 })
184 })
185 }
186 pub fn EOI(s: BoxedState<'_>) -> ParseResult<'_> {
187 s.rule(Rule::EOI, |s| s.end_of_input())
188 }
189}
190
191pub fn pest_parse(input: &str) -> std::result::Result<pest::iterators::Pairs<'_, Rule>, PestError> {
192 pest::state(input, rules::vdf)
193}