keyvalues_parser/text/parse/
raw.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, 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 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}