Skip to main content

openpql_pql_parser/ast/
num.rs

1use super::{Error, LalrError, Loc, LocInfo, NumValueFloat, NumValueInt, Spanned, str};
2
3impl Spanned for Num {
4    fn loc(&self) -> LocInfo {
5        self.loc
6    }
7}
8
9/// Numeric literal with its parsed value and source span.
10#[derive(Clone, PartialEq, derive_more::From, derive_more::Debug)]
11#[debug("{}", self.inner)]
12pub struct Num {
13    /// Parsed numeric value.
14    pub inner: NumValue,
15    /// Source span of the literal.
16    pub loc: (Loc, Loc),
17}
18
19impl From<(NumValueFloat, (Loc, Loc))> for Num {
20    fn from((val, loc): (NumValueFloat, (Loc, Loc))) -> Self {
21        Self {
22            inner: val.into(),
23            loc,
24        }
25    }
26}
27
28impl From<(NumValueInt, (Loc, Loc))> for Num {
29    fn from((val, loc): (NumValueInt, (Loc, Loc))) -> Self {
30        Self {
31            inner: val.into(),
32            loc,
33        }
34    }
35}
36
37/// # Panics
38/// float parse won't fail /-?(\d+)?\.\d+/
39/// <https://doc.rust-lang.org/std/primitive.f64.html#method.from_str>
40impl<'input> TryFrom<(&'input str, (Loc, Loc), bool)> for Num {
41    type Error = LalrError<'input>;
42
43    fn try_from(
44        (src, loc, is_float): (&'input str, (Loc, Loc), bool),
45    ) -> Result<Self, Self::Error> {
46        if is_float {
47            Ok((src.parse::<NumValueFloat>().unwrap(), loc).into())
48        } else {
49            src.parse::<NumValueInt>().map_or_else(
50                |_| Err(Error::InvalidNumericValue(loc).into()),
51                |v| Ok((v, loc).into()),
52            )
53        }
54    }
55}
56
57/// Parsed numeric value, either integer or floating-point.
58#[derive(Clone, Copy, Debug, PartialEq, derive_more::From, derive_more::Display)]
59pub enum NumValue {
60    /// Integer value.
61    #[display("{_0}")]
62    Int(NumValueInt),
63    /// Floating-point value.
64    #[display("{_0}")]
65    Float(NumValueFloat),
66}
67
68#[cfg(test)]
69mod tests {
70
71    use super::*;
72    use crate::*;
73
74    fn assert_num<T>(src: &str, expected: T)
75    where
76        NumValue: From<T>,
77    {
78        let loc_start = 0;
79        let loc_end = src.len();
80        assert_eq!(
81            parse_num(src),
82            Ok((NumValue::from(expected), (loc_start, loc_end)).into())
83        );
84    }
85
86    #[test]
87    fn test_num() {
88        assert_num("0", 0);
89        assert_num("-1", -1);
90        assert_num("-1.5", -1.5);
91        assert_num("-.5", -0.5);
92        assert_num(".5", 0.5);
93    }
94
95    #[test]
96    fn test_err() {
97        let toobig = format!("{}0", NumValueInt::MAX);
98        assert_eq!(
99            parse_num(&toobig),
100            Err(Error::InvalidNumericValue((0, toobig.len())))
101        );
102    }
103
104    #[test]
105    fn test_dbg() {
106        assert_eq!(format!("{:?}", Num::from((-123, (0, 1)))), "-123");
107    }
108
109    #[test]
110    fn test_loc() {
111        let n = Num::from((-1, (4, 6)));
112        assert_eq!(n.loc(), (4, 6));
113    }
114}