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::{SourceInfo, Template, TemplateElement};
19
use crate::parser::primitives::try_literal;
20
use crate::parser::{string, ParseError, ParseErrorKind, ParseResult};
21
use crate::reader::Reader;
22

            
23
use super::placeholder;
24

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

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

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

            
98
95105
fn key_string_text(reader: &mut Reader) -> String {
99
95105
    let mut s = String::new();
100
    loop {
101
298680
        let save = reader.cursor();
102
298680
        match reader.read() {
103
325
            None => break,
104
298355
            Some(c) => {
105
298355
                if c.is_alphanumeric()
106
119050
                    || c == '_'
107
118105
                    || c == '-'
108
116505
                    || c == '.'
109
116450
                    || c == '['
110
105680
                    || c == ']'
111
94915
                    || c == '@'
112
94860
                    || c == '$'
113
203575
                {
114
203575
                    s.push(c);
115
203575
                } else {
116
94780
                    reader.seek(save);
117
94780
                    break;
118
                }
119
            }
120
        }
121
    }
122

            
123
95105
    s
124
}
125

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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