Skip to main content

java_props/
parser.rs

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    // skip "\"
60    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}