taitan_orm_parser/template_parser/structs/
number.rs

1use nom::branch::alt;
2use nom::bytes::complete::{tag, take_while1};
3use nom::character::complete::{digit1, multispace0};
4use nom::combinator::{map, opt, recognize};
5use nom::sequence::{preceded, terminated, tuple};
6use nom::IResult;
7use std::fmt::Display;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Number {
11    pub value: String,
12    pub unary_op: Option<char>,
13}
14
15impl Number {
16    pub fn parse(input: &str) -> IResult<&str, Number> {
17        alt((parse_hex, parse_decimal))(input)
18    }
19
20    pub fn set_unary_op(mut self, unary_op: char) {
21        assert!(unary_op == '-' || unary_op == '+');
22        self.unary_op = Some(unary_op)
23    }
24}
25
26fn parse_decimal(input: &str) -> IResult<&str, Number> {
27    map(
28        recognize(tuple((
29            // opt(char('-')),                   // 可选的负号
30            // opt(char('+')),                   // 可选的正号
31            digit1, // 整数部分
32            opt(preceded(
33                multispace0,
34                preceded(
35                    nom::character::complete::char('.'),
36                    preceded(multispace0, digit1),
37                ),
38            )), // 可选的小数部分
39        ))),
40        |s: &str| Number {
41            value: s.to_string(),
42            unary_op: None,
43        },
44    )(input)
45}
46
47fn parse_hex(input: &str) -> IResult<&str, Number> {
48    map(
49        recognize(alt((
50            // 解析 0x1A 格式
51            preceded(tag("0x"), take_while1(|c: char| c.is_ascii_hexdigit())),
52            // 解析 x'1A' 格式
53            preceded(
54                tuple((tag("x"), nom::character::complete::char('\''))),
55                terminated(
56                    take_while1(|c: char| c.is_ascii_hexdigit()),
57                    nom::character::complete::char('\''),
58                ),
59            ),
60        ))),
61        |s: &str| Number {
62            value: s.to_string(),
63            unary_op: None,
64        },
65    )(input)
66}
67
68impl Display for Number {
69    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match &self.unary_op {
71            Some(unary_op) => fmt.write_fmt(format_args!("{}{}", unary_op, self.value)),
72            None => fmt.write_fmt(format_args!("{}", self.value)),
73        }
74    }
75}
76
77#[cfg(test)]
78mod num_parse_tests {
79    use crate::Number;
80
81    #[test]
82    fn test_number_parse() {
83        let template = "123 . 123";
84        let (_, parsed) = Number::parse(template).unwrap();
85        assert_eq!(
86            parsed,
87            Number {
88                value: "123 . 123".to_string(),
89                unary_op: None
90            }
91        );
92    }
93    #[test]
94    fn test_hex_number_parse() {
95        let template = "0x123";
96        let (_, parsed) = Number::parse(template).unwrap();
97        assert_eq!(
98            parsed,
99            Number {
100                value: "0x123".to_string(),
101                unary_op: None
102            }
103        );
104
105        let template = "x\'123\'";
106        let (_, parsed) = Number::parse(template).unwrap();
107        assert_eq!(
108            parsed,
109            Number {
110                value: "x\'123\'".to_string(),
111                unary_op: None
112            }
113        );
114    }
115}