1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2025 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::{Expr, ExprKind, SourceInfo, Variable};
19
use crate::parser::{function, ParseError, ParseErrorKind, ParseResult};
20
use crate::reader::Reader;
21

            
22
/// Parse an expression
23
///
24
/// Currently, an expression can only be found inside a placeholder
25
2460
pub fn parse(reader: &mut Reader) -> ParseResult<Expr> {
26
2460
    let start = reader.cursor().pos;
27
2460
    let save_state = reader.cursor();
28
2460
    let kind = match function::parse(reader) {
29
40
        Ok(function) => ExprKind::Function(function),
30
2420
        Err(e) => {
31
2420
            if e.recoverable {
32
2420
                reader.seek(save_state);
33
2420
                let variable = variable_name(reader)?;
34
2415
                ExprKind::Variable(variable)
35
            } else {
36
                return Err(e);
37
            }
38
        }
39
    };
40
2455
    let end = reader.cursor().pos;
41
2455
    let source_info = SourceInfo::new(start, end);
42
2455
    Ok(Expr { source_info, kind })
43
}
44

            
45
2420
fn variable_name(reader: &mut Reader) -> ParseResult<Variable> {
46
2420
    let start = reader.cursor();
47
17509
    let name = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
48
2420
    if name.is_empty() {
49
5
        return Err(ParseError::new(
50
5
            start.pos,
51
5
            false,
52
5
            ParseErrorKind::TemplateVariable,
53
5
        ));
54
    }
55
2415
    Ok(Variable {
56
2415
        name,
57
2415
        source_info: SourceInfo::new(start.pos, reader.cursor().pos),
58
2415
    })
59
}
60

            
61
#[cfg(test)]
62
mod tests {
63
    use super::*;
64
    use crate::reader::Pos;
65

            
66
    #[test]
67
    fn test_variable() {
68
        let mut reader = Reader::new("name");
69
        assert_eq!(
70
            variable_name(&mut reader).unwrap(),
71
            Variable {
72
                name: String::from("name"),
73
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
74
            }
75
        );
76

            
77
        let mut reader = Reader::new("my-id");
78
        assert_eq!(
79
            variable_name(&mut reader).unwrap(),
80
            Variable {
81
                name: String::from("my-id"),
82
                source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 6)),
83
            }
84
        );
85
    }
86
}