Skip to main content

openpql_pql_parser/ast/
num.rs

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