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::ParseResult;
20
use crate::parser::{function, ParseError, ParseErrorKind};
21
use crate::reader::Reader;
22

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

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

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

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

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