1use crate::{PropertyValue, PropertyRange, PropertyData, PropertyType::*};
2use crate::Iterator;
3
4pub fn read_whitespace(iter: &mut Iterator) -> PropertyValue {
5 let start = iter.position;
6
7 while match iter.peek() {
8 Some(chr) => chr.is_whitespace(),
9 None => false,
10 } {
11 iter.next();
12 }
13
14 PropertyValue {
15 data: PropertyData::Range(PropertyRange {
16 start,
17 end: iter.position,
18 }),
19 children: None,
20 type_: Whitespace,
21 }
22}
23
24pub fn is_comment_indicator(chr: char) -> bool {
25 chr == '#' || chr == '!'
26}
27
28pub fn is_eol(chr: char) -> bool {
29 chr == '\n' || chr == '\r'
30}
31
32pub fn read_comment(iter: &mut Iterator) -> PropertyValue {
33 let start = iter.position;
34
35 while match iter.peek() {
36 Some(chr) => !is_eol(chr),
37 None => false
38 } {
39 iter.next();
40 }
41
42 PropertyValue {
43 data: PropertyData::Range(PropertyRange {
44 start,
45 end: iter.position,
46 }),
47 children: None,
48 type_: Comment,
49 }
50}
51
52pub fn starts_escaped_value(chr: char) -> bool {
53 chr == '\\'
54}
55
56pub fn read_escaped_value(iter: &mut Iterator) -> PropertyValue {
57 let start = iter.position;
58
59 iter.next();
61
62 let chr = iter.next();
63 if chr.is_some() {
64 let chr = chr.unwrap();
65
66 if chr == 'u' {
67 iter.next_x(4);
68 }
69 }
70
71 PropertyValue {
72 data: PropertyData::Range(PropertyRange {
73 start,
74 end: iter.position,
75 }),
76 children: None,
77 type_: EscapedValue,
78 }
79}
80
81pub fn starts_separator(chr: char) -> bool {
82 chr == '=' || chr == ':' || chr.is_whitespace()
83}
84
85pub fn read_key(iter: &mut Iterator) -> PropertyValue {
86 let start = iter.position;
87 let mut children = Vec::new();
88
89 while iter.peek().is_some() {
90 let chr = iter.peek().unwrap();
91
92 if starts_separator(chr) {
93 break;
94 }
95
96 if starts_escaped_value(chr) {
97 children.push(read_escaped_value(iter));
98 continue;
99 }
100
101 iter.next();
102 }
103
104 PropertyValue {
105 data: PropertyData::Range(PropertyRange {
106 start,
107 end: iter.position,
108 }),
109 children: Some(children),
110 type_: Key,
111 }
112}
113
114pub fn read_property(iter: &mut Iterator) -> PropertyValue {
115 let start = iter.position;
116 let children = vec![
117 read_key(iter),
118 read_separator(iter),
119 read_value(iter),
120 ];
121
122 PropertyValue {
123 data: PropertyData::Range(PropertyRange {
124 start,
125 end: iter.position,
126 }),
127 children: Some(children),
128 type_: Property,
129 }
130}
131
132pub fn read_separator(iter: &mut Iterator) -> PropertyValue {
133 let start = iter.position;
134 let mut after_separator = false;
135
136 while iter.peek().is_some() {
137 let chr = iter.peek().unwrap();
138
139 if is_eol(chr) {
140 break;
141 }
142
143 if chr.is_whitespace() {
144 iter.next();
145 continue;
146 }
147
148 if after_separator {
149 break;
150 }
151
152 after_separator = chr == ':' || chr == '=';
153
154 if after_separator {
155 iter.next();
156 continue;
157 }
158
159 break;
160 }
161
162 PropertyValue {
163 data: PropertyData::Range(PropertyRange {
164 start,
165 end: iter.position,
166 }),
167 children: None,
168 type_: Separator,
169 }
170}
171
172pub fn starts_line_break(iter: &mut Iterator) -> bool {
173 iter.peek().unwrap() == '\\' && is_eol(iter.peek_x(1).unwrap())
174}
175
176pub fn read_line_break(iter: &mut Iterator) -> PropertyValue {
177 let start = iter.position;
178
179 iter.next();
180
181 if let Some(chr) = iter.peek() {
182 if chr == '\r' {
183 iter.next();
184 }
185 }
186
187 iter.next();
188
189 while iter.peek().is_some() {
190 let chr = iter.peek().unwrap();
191
192 if is_eol(chr) || !chr.is_whitespace() {
193 break;
194 }
195
196 iter.next();
197 }
198
199 PropertyValue {
200 data: PropertyData::Range(PropertyRange {
201 start,
202 end: iter.position,
203 }),
204 children: None,
205 type_: LineBreak,
206 }
207}
208
209pub fn read_value(iter: &mut Iterator) -> PropertyValue {
210 let start = iter.position;
211 let mut children = Vec::new();
212
213 while iter.peek().is_some() {
214 let chr = iter.peek().unwrap();
215
216 if starts_line_break(iter) {
217 children.push(read_line_break(iter));
218 continue;
219 }
220
221 if starts_escaped_value(chr) {
222 children.push(read_escaped_value(iter));
223 continue;
224 }
225
226 if is_eol(chr) {
227 break;
228 }
229
230 iter.next();
231 }
232
233 PropertyValue {
234 data: PropertyData::Range(PropertyRange {
235 start,
236 end: iter.position,
237 }),
238 children: Some(children),
239 type_: Value,
240 }
241}