csml_interpreter/parser/
parse_literal.rs

1use crate::data::{ast::*, tokens::*, Literal};
2use crate::parser::tools::get_string;
3use crate::parser::tools::get_tag;
4use crate::parser::{parse_comments::comment, tools::get_interval};
5
6use crate::data::primitive::{
7    boolean::PrimitiveBoolean, float::PrimitiveFloat, int::PrimitiveInt, null::PrimitiveNull,
8};
9use nom::{
10    branch::alt,
11    bytes::complete::tag,
12    character::complete::{char, one_of},
13    combinator::{opt, recognize},
14    error::{ContextError, ParseError},
15    multi::{many0, many1},
16    sequence::{preceded, terminated, tuple},
17    IResult,
18};
19
20////////////////////////////////////////////////////////////////////////////////
21// PRIVATE FUNCTIONS
22////////////////////////////////////////////////////////////////////////////////
23
24fn signed_digits<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Span, E>
25where
26    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
27{
28    recognize(tuple((opt(one_of("+-")), decimal)))(s)
29}
30
31fn decimal<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Span, E>
32where
33    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
34{
35    recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(s)
36}
37
38fn parse_integer<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
39where
40    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
41{
42    let (s, interval) = get_interval(s)?;
43    let (s, int) = get_int(s)?;
44
45    let expression = Expr::LitExpr {
46        literal: PrimitiveInt::get_literal(int, interval),
47        in_in_substring: false,
48    };
49    Ok((s, expression))
50}
51
52fn floating_point<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Span<'a>, E>
53where
54    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
55{
56    alt((
57        // Case one: .42
58        recognize(tuple((char('.'), decimal))), // Case two: 42.42
59        recognize(tuple((
60            opt(one_of("+-")),
61            decimal,
62            preceded(char('.'), decimal),
63        ))),
64    ))(s)
65}
66
67fn parse_float<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
68where
69    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
70{
71    let (s, interval) = get_interval(s)?;
72    let (s, float_raw) = floating_point(s)?;
73    let float = float_raw.fragment().parse::<f64>().unwrap_or(0.0);
74
75    let expression = Expr::LitExpr {
76        literal: PrimitiveFloat::get_literal(float, interval),
77        in_in_substring: false,
78    };
79
80    Ok((s, expression))
81}
82
83fn parse_number<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
84where
85    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
86{
87    alt((parse_float, parse_integer))(s)
88}
89
90fn parse_true<'a, E>(s: Span<'a>) -> IResult<Span<'a>, PrimitiveBoolean, E>
91where
92    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
93{
94    let (s, _) = tag(TRUE)(s)?;
95
96    Ok((s, PrimitiveBoolean::new(true)))
97}
98
99fn parse_false<'a, E>(s: Span<'a>) -> IResult<Span<'a>, PrimitiveBoolean, E>
100where
101    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
102{
103    let (s, _) = tag(FALSE)(s)?;
104
105    Ok((s, PrimitiveBoolean::new(false)))
106}
107
108fn parse_boolean<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
109where
110    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
111{
112    let (s, interval) = get_interval(s)?;
113    let (s, boolean) = alt((parse_true, parse_false))(s)?;
114
115    let primitive = Box::new(boolean);
116    let expression = Expr::LitExpr {
117        literal: Literal {
118            content_type: "boolean".to_owned(),
119            primitive,
120            additional_info: None,
121            secure_variable: false,
122            interval,
123        },
124        in_in_substring: false,
125    };
126
127    Ok((s, expression))
128}
129
130fn parse_null<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
131where
132    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
133{
134    let (s, interval) = get_interval(s)?;
135    let (s, name) = preceded(comment, get_string)(s)?;
136    let (s, _) = get_tag(name.to_ascii_lowercase(), NULL)(s)?;
137
138    let expression = Expr::LitExpr {
139        literal: PrimitiveNull::get_literal(interval),
140        in_in_substring: false,
141    };
142
143    Ok((s, expression))
144}
145
146////////////////////////////////////////////////////////////////////////////////
147// PUBLIC FUNCTION
148////////////////////////////////////////////////////////////////////////////////
149
150pub fn get_int<'a, E>(s: Span<'a>) -> IResult<Span<'a>, i64, E>
151where
152    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
153{
154    // map_res(signed_digits, |s: Span| s.fragment().parse::<i64>())(s)
155    let (s, raw_digits) = signed_digits(s)?;
156    let int = raw_digits.fragment().parse::<i64>().unwrap_or(0);
157
158    Ok((s, int))
159}
160
161pub fn parse_literal_expr<'a, E>(s: Span<'a>) -> IResult<Span<'a>, Expr, E>
162where
163    E: ParseError<Span<'a>> + ContextError<Span<'a>>,
164{
165    // TODO: span: preceded( comment ,  position!() ?
166    preceded(comment, alt((parse_number, parse_boolean, parse_null)))(s)
167}
168
169////////////////////////////////////////////////////////////////////////////////
170// TEST FUNCTIONS
171////////////////////////////////////////////////////////////////////////////////
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176    use nom::{error::ErrorKind, *};
177
178    pub fn test_literal(s: Span) -> IResult<Span, Expr> {
179        let var = parse_literal_expr(s);
180        if let Ok((s, v)) = var {
181            if s.fragment().len() != 0 {
182                Err(Err::Error(nom::error::Error::new(s, ErrorKind::Tag)))
183            } else {
184                Ok((s, v))
185            }
186        } else {
187            var
188        }
189    }
190
191    #[test]
192    fn ok_int() {
193        let string = Span::new(" +42");
194        match test_literal(string) {
195            Ok(..) => {}
196            Err(e) => panic!("{:?}", e),
197        }
198    }
199
200    #[test]
201    fn ok_float() {
202        let string = Span::new(" -42.42");
203        match test_literal(string) {
204            Ok(..) => {}
205            Err(e) => panic!("{:?}", e),
206        }
207    }
208
209    #[test]
210    fn ok_bool() {
211        let string = Span::new(" true");
212        match test_literal(string) {
213            Ok(..) => {}
214            Err(e) => panic!("{:?}", e),
215        }
216    }
217
218    #[test]
219    fn err_sign() {
220        let string = Span::new(" +++++4");
221        match test_literal(string) {
222            Ok(..) => panic!("need to fail"),
223            Err(..) => {}
224        }
225    }
226
227    #[test]
228    fn err_float1() {
229        let string = Span::new(" 2.2.2");
230        match test_literal(string) {
231            Ok(..) => panic!("need to fail"),
232            Err(..) => {}
233        }
234    }
235
236    #[test]
237    fn err_float2() {
238        let string = Span::new(" 3,2 ");
239        match test_literal(string) {
240            Ok(ok) => panic!("need to fail {:?}", ok),
241            Err(..) => {}
242        }
243    }
244}