libcst_native/parser/
numbers.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree
5
6use regex::Regex;
7
8use crate::nodes::deflated::{Expression, Float, Imaginary, Integer};
9
10static HEX: &str = r"0[xX](?:_?[0-9a-fA-F])+";
11static BIN: &str = r"0[bB](?:_?[01])+";
12static OCT: &str = r"0[oO](?:_?[0-7])+";
13static DECIMAL: &str = r"(?:0(?:_?0)*|[1-9](?:_?[0-9])*)";
14
15static EXPONENT: &str = r"[eE][-+]?[0-9](?:_?[0-9])*";
16// Note: these don't exactly match the python implementation (exponent is not included)
17static POINT_FLOAT: &str = r"([0-9](?:_?[0-9])*\.(?:[0-9](?:_?[0-9])*)?|\.[0-9](?:_?[0-9])*)";
18static EXP_FLOAT: &str = r"[0-9](?:_?[0-9])*";
19
20thread_local! {
21    static INTEGER_RE: Regex =
22        Regex::new(format!("^({}|{}|{}|{})$", HEX, BIN, OCT, DECIMAL).as_str()).expect("regex");
23    static FLOAT_RE: Regex =
24        Regex::new(
25            format!(
26                "^({}({})?|{}{})$",
27                POINT_FLOAT, EXPONENT, EXP_FLOAT, EXPONENT
28            )
29            .as_str(),
30        )
31        .expect("regex");
32    static IMAGINARY_RE: Regex =
33        Regex::new(
34            format!(
35                r"^([0-9](?:_?[0-9])*[jJ]|({}({})?|{}{})[jJ])$",
36                POINT_FLOAT, EXPONENT, EXP_FLOAT, EXPONENT
37            )
38            .as_str(),
39        )
40        .expect("regex");
41}
42
43pub(crate) fn parse_number(raw: &str) -> Expression {
44    if INTEGER_RE.with(|r| r.is_match(raw)) {
45        Expression::Integer(Box::new(Integer {
46            value: raw,
47            lpar: Default::default(),
48            rpar: Default::default(),
49        }))
50    } else if FLOAT_RE.with(|r| r.is_match(raw)) {
51        Expression::Float(Box::new(Float {
52            value: raw,
53            lpar: Default::default(),
54            rpar: Default::default(),
55        }))
56    } else if IMAGINARY_RE.with(|r| r.is_match(raw)) {
57        Expression::Imaginary(Box::new(Imaginary {
58            value: raw,
59            lpar: Default::default(),
60            rpar: Default::default(),
61        }))
62    } else {
63        Expression::Integer(Box::new(Integer {
64            value: raw,
65            lpar: Default::default(),
66            rpar: Default::default(),
67        }))
68    }
69}