1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2024 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use crate::ast::*;
19
use crate::parser::error::*;
20
use crate::parser::primitives::*;
21
use crate::parser::{string, ParseResult};
22
use crate::reader::Reader;
23

            
24
use super::placeholder;
25

            
26
32950
pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
27
32950
    let start = reader.cursor();
28
32950
    let mut elements = vec![];
29
    loop {
30
63985
        let save_state = reader.cursor();
31
63985
        match placeholder::parse(reader) {
32
210
            Ok(placeholder) => {
33
210
                let element = TemplateElement::Placeholder(placeholder);
34
210
                elements.push(element);
35
            }
36
63775
            Err(e) => {
37
63775
                if e.recoverable {
38
63775
                    reader.seek(save_state);
39
63775
                    let value = key_string_content(reader)?;
40
63775
                    if value.is_empty() {
41
32950
                        break;
42
                    }
43
30825
                    let encoded = reader.read_from(start.index);
44
30825
                    let element = TemplateElement::String { value, encoded };
45
30825
                    elements.push(element);
46
                } else {
47
                    return Err(e);
48
                }
49
            }
50
        }
51
    }
52
32950
    if elements.is_empty() {
53
1915
        let kind = ParseErrorKind::Expecting {
54
1915
            value: "key-string".to_string(),
55
1915
        };
56
1915
        return Err(ParseError::new(start.pos, false, kind));
57
    }
58
31035
    if let Some(TemplateElement::String { encoded, .. }) = elements.first() {
59
30825
        if encoded.starts_with('[') {
60
10670
            let kind = ParseErrorKind::Expecting {
61
10670
                value: "key-string".to_string(),
62
10670
            };
63
10670
            return Err(ParseError::new(start.pos, false, kind));
64
        }
65
    }
66

            
67
20365
    let end = reader.cursor();
68
20365
    Ok(Template {
69
20365
        delimiter: None,
70
20365
        elements,
71
20365
        source_info: SourceInfo::new(start.pos, end.pos),
72
20365
    })
73
}
74

            
75
63775
fn key_string_content(reader: &mut Reader) -> ParseResult<String> {
76
63775
    let mut s = String::new();
77
    loop {
78
94720
        match key_string_escaped_char(reader) {
79
80
            Ok(c) => {
80
80
                s.push(c);
81
            }
82
94640
            Err(e) => {
83
94640
                if e.recoverable {
84
94640
                    let s2 = key_string_text(reader);
85
94640
                    if s2.is_empty() {
86
63775
                        break;
87
30865
                    } else {
88
30865
                        s.push_str(&s2);
89
                    }
90
                } else {
91
                    return Err(e);
92
                }
93
            }
94
        }
95
    }
96
63775
    Ok(s)
97
}
98

            
99
94640
fn key_string_text(reader: &mut Reader) -> String {
100
94640
    let mut s = String::new();
101
    loop {
102
297100
        let save = reader.cursor();
103
297100
        match reader.read() {
104
330
            None => break,
105
296770
            Some(c) => {
106
296770
                if c.is_alphanumeric()
107
118395
                    || c == '_'
108
117450
                    || c == '-'
109
115915
                    || c == '.'
110
115860
                    || c == '['
111
105150
                    || c == ']'
112
94445
                    || c == '@'
113
94390
                    || c == '$'
114
202460
                {
115
202460
                    s.push(c);
116
202460
                } else {
117
94310
                    reader.seek(save);
118
94310
                    break;
119
                }
120
            }
121
        }
122
    }
123

            
124
94640
    s
125
}
126

            
127
94720
fn key_string_escaped_char(reader: &mut Reader) -> ParseResult<char> {
128
94720
    try_literal("\\", reader)?;
129
80
    let start = reader.cursor();
130
80
    match reader.read() {
131
        Some('#') => Ok('#'),
132
        Some(':') => Ok(':'),
133
        Some('\\') => Ok('\\'),
134
        Some('/') => Ok('/'),
135
        Some('b') => Ok('\x08'),
136
        Some('f') => Ok('\x0c'),
137
        Some('n') => Ok('\n'),
138
        Some('r') => Ok('\r'),
139
        Some('t') => Ok('\t'),
140
80
        Some('u') => string::unicode(reader),
141
        _ => Err(ParseError::new(
142
            start.pos,
143
            false,
144
            ParseErrorKind::EscapeChar,
145
        )),
146
    }
147
}
148

            
149
#[cfg(test)]
150
mod tests {
151
    use super::*;
152
    use crate::reader::Pos;
153

            
154
    #[test]
155
    fn test_key_string() {
156
        let mut reader = Reader::new("aaa\\: ");
157
        assert_eq!(
158
            parse(&mut reader).unwrap(),
159
            Template {
160
                delimiter: None,
161
                elements: vec![TemplateElement::String {
162
                    value: "aaa:".to_string(),
163
                    encoded: "aaa\\:".to_string(),
164
                }],
165
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 6)),
166
            }
167
        );
168
        assert_eq!(reader.cursor().index, 5);
169

            
170
        let mut reader = Reader::new("$top:");
171
        assert_eq!(
172
            parse(&mut reader).unwrap(),
173
            Template {
174
                delimiter: None,
175
                elements: vec![TemplateElement::String {
176
                    value: "$top".to_string(),
177
                    encoded: "$top".to_string(),
178
                }],
179
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
180
            }
181
        );
182
        assert_eq!(reader.cursor().index, 4);
183

            
184
        let mut reader = Reader::new("key\\u{20}\\u{3a} :");
185
        assert_eq!(
186
            parse(&mut reader).unwrap(),
187
            Template {
188
                delimiter: None,
189
                elements: vec![TemplateElement::String {
190
                    value: "key :".to_string(),
191
                    encoded: "key\\u{20}\\u{3a}".to_string(),
192
                }],
193
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 16)),
194
            }
195
        );
196
        assert_eq!(reader.cursor().index, 15);
197

            
198
        let mut reader = Reader::new("values\\u{5b}0\\u{5d} :");
199
        assert_eq!(
200
            parse(&mut reader).unwrap(),
201
            Template {
202
                delimiter: None,
203
                elements: vec![TemplateElement::String {
204
                    value: "values[0]".to_string(),
205
                    encoded: "values\\u{5b}0\\u{5d}".to_string(),
206
                }],
207
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 20)),
208
            }
209
        );
210
        assert_eq!(reader.cursor().index, 19);
211

            
212
        let mut reader = Reader::new("values[0] :");
213
        assert_eq!(
214
            parse(&mut reader).unwrap(),
215
            Template {
216
                delimiter: None,
217
                elements: vec![TemplateElement::String {
218
                    value: "values[0]".to_string(),
219
                    encoded: "values[0]".to_string(),
220
                }],
221
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 10)),
222
            }
223
        );
224
        assert_eq!(reader.cursor().index, 9);
225

            
226
        let mut reader = Reader::new("\\u{5b}0\\u{5d}");
227
        assert_eq!(
228
            parse(&mut reader).unwrap(),
229
            Template {
230
                delimiter: None,
231
                elements: vec![TemplateElement::String {
232
                    value: "[0]".to_string(),
233
                    encoded: "\\u{5b}0\\u{5d}".to_string(),
234
                }],
235
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 14)),
236
            }
237
        );
238
        assert_eq!(reader.cursor().index, 13);
239
    }
240

            
241
    #[test]
242
    fn test_key_string_error() {
243
        let mut reader = Reader::new("");
244
        let error = parse(&mut reader).err().unwrap();
245
        assert!(!error.recoverable);
246
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
247

            
248
        let mut reader = Reader::new("{{key");
249
        let error = parse(&mut reader).err().unwrap();
250
        assert!(!error.recoverable);
251
        assert_eq!(error.pos, Pos { line: 1, column: 6 });
252

            
253
        // key string can not start with a '[' (reserved for section)
254
        let mut reader = Reader::new("[0]:");
255
        let error = parse(&mut reader).err().unwrap();
256
        assert!(!error.recoverable);
257
        assert_eq!(reader.cursor().index, 3);
258

            
259
        let mut reader = Reader::new("\\l");
260
        let error = parse(&mut reader).err().unwrap();
261
        assert_eq!(error.pos, Pos { line: 1, column: 2 });
262
        assert_eq!(error.kind, ParseErrorKind::EscapeChar);
263

            
264
        let mut reader = Reader::new(r#"{"id":1}"#);
265
        let error = parse(&mut reader).err().unwrap();
266
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
267
        assert_eq!(
268
            error.kind,
269
            ParseErrorKind::Expecting {
270
                value: "key-string".to_string()
271
            }
272
        );
273
    }
274

            
275
    #[test]
276
    fn test_key_string_content() {
277
        let mut reader = Reader::new("aaa\\:");
278
        assert_eq!(key_string_content(&mut reader).unwrap(), "aaa:");
279
    }
280

            
281
    #[test]
282
    fn test_key_string_text() {
283
        let mut reader = Reader::new("aaa\\:");
284
        assert_eq!(key_string_text(&mut reader), "aaa");
285
        assert_eq!(reader.cursor().index, 3);
286
    }
287

            
288
    #[test]
289
    fn test_key_string_escaped_char() {
290
        let mut reader = Reader::new("\\u{0a}");
291
        assert_eq!(key_string_escaped_char(&mut reader).unwrap(), '\n');
292
        assert_eq!(reader.cursor().index, 6);
293

            
294
        let mut reader = Reader::new("\\:");
295
        assert_eq!(key_string_escaped_char(&mut reader).unwrap(), ':');
296
        assert_eq!(reader.cursor().index, 2);
297

            
298
        let mut reader = Reader::new("x");
299
        let error = key_string_escaped_char(&mut reader).err().unwrap();
300
        assert_eq!(error.pos, Pos { line: 1, column: 1 });
301
        assert_eq!(
302
            error.kind,
303
            ParseErrorKind::Expecting {
304
                value: "\\".to_string()
305
            }
306
        );
307
        assert!(error.recoverable);
308
        assert_eq!(reader.cursor().index, 0);
309
    }
310
}