1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2026 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::Placeholder;
19
use crate::reader::Reader;
20

            
21
use super::primitives::{literal, try_literal, zero_or_more_spaces};
22
use super::{ParseResult, expr};
23

            
24
/// Parse a placeholder {{ expr }}
25
104488
pub fn parse(reader: &mut Reader) -> ParseResult<Placeholder> {
26
104488
    try_literal("{{", reader)?;
27
1388
    let space0 = zero_or_more_spaces(reader)?;
28
1388
    let expr = expr::parse(reader)?;
29
1388
    let space1 = zero_or_more_spaces(reader)?;
30
1388
    literal("}}", reader)?;
31
1388
    Ok(Placeholder {
32
1388
        space0,
33
1388
        expr,
34
1388
        space1,
35
1388
    })
36
}
37

            
38
#[cfg(test)]
39
mod tests {
40
    use crate::ast::{Expr, ExprKind, SourceInfo, Variable, Whitespace};
41
    use crate::parser::ParseErrorKind;
42
    use crate::reader::Pos;
43

            
44
    use super::*;
45

            
46
    #[test]
47
    fn test_ok() {
48
        let mut reader = Reader::new("{{ name}}");
49
        assert_eq!(
50
            parse(&mut reader).unwrap(),
51
            Placeholder {
52
                space0: Whitespace {
53
                    value: String::from(" "),
54
                    source_info: SourceInfo::new(Pos::new(1, 3), Pos::new(1, 4)),
55
                },
56
                expr: Expr {
57
                    kind: ExprKind::Variable(Variable {
58
                        name: "name".to_string(),
59
                        source_info: SourceInfo::new(Pos::new(1, 4), Pos::new(1, 8)),
60
                    }),
61
                    source_info: SourceInfo::new(Pos::new(1, 4), Pos::new(1, 8)),
62
                },
63
                space1: Whitespace {
64
                    value: String::new(),
65
                    source_info: SourceInfo::new(Pos::new(1, 8), Pos::new(1, 8)),
66
                },
67
            }
68
        );
69
    }
70

            
71
    #[test]
72
    fn test_error() {
73
        let mut reader = Reader::new("{{host>}}");
74
        let error = parse(&mut reader).err().unwrap();
75
        assert_eq!(error.pos, Pos { line: 1, column: 7 });
76
        assert_eq!(
77
            error.kind,
78
            ParseErrorKind::Expecting {
79
                value: String::from("}}")
80
            }
81
        );
82
        assert!(!error.recoverable);
83
    }
84

            
85
    #[test]
86
    fn test_error_eof() {
87
        let mut reader = Reader::new("{{host");
88
        let error = parse(&mut reader).err().unwrap();
89
        assert_eq!(error.pos, Pos { line: 1, column: 7 });
90
        assert_eq!(
91
            error.kind,
92
            ParseErrorKind::Expecting {
93
                value: String::from("}}")
94
            }
95
        );
96
        assert!(!error.recoverable);
97
    }
98
}