taitan_orm_parser/template_parser/structs/
number.rs1use 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 digit1, opt(preceded(
33 multispace0,
34 preceded(
35 nom::character::complete::char('.'),
36 preceded(multispace0, digit1),
37 ),
38 )), ))),
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 preceded(tag("0x"), take_while1(|c: char| c.is_ascii_hexdigit())),
52 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}