1"""
2Formatting numeric literals.
3"""
4from blib2to3.pytree import Leaf
5
6
7def format_hex(text: str) -> str:
8    """
9    Formats a hexadecimal string like "0x12B3"
10    """
11    before, after = text[:2], text[2:]
12    return f"{before}{after.upper()}"
13
14
15def format_scientific_notation(text: str) -> str:
16    """Formats a numeric string utilizing scentific notation"""
17    before, after = text.split("e")
18    sign = ""
19    if after.startswith("-"):
20        after = after[1:]
21        sign = "-"
22    elif after.startswith("+"):
23        after = after[1:]
24    before = format_float_or_int_string(before)
25    return f"{before}e{sign}{after}"
26
27
28def format_long_or_complex_number(text: str) -> str:
29    """Formats a long or complex string like `10L` or `10j`"""
30    number = text[:-1]
31    suffix = text[-1]
32    # Capitalize in "2L" because "l" looks too similar to "1".
33    if suffix == "l":
34        suffix = "L"
35    return f"{format_float_or_int_string(number)}{suffix}"
36
37
38def format_float_or_int_string(text: str) -> str:
39    """Formats a float string like "1.0"."""
40    if "." not in text:
41        return text
42
43    before, after = text.split(".")
44    return f"{before or 0}.{after or 0}"
45
46
47def normalize_numeric_literal(leaf: Leaf) -> None:
48    """Normalizes numeric (float, int, and complex) literals.
49
50    All letters used in the representation are normalized to lowercase (except
51    in Python 2 long literals).
52    """
53    text = leaf.value.lower()
54    if text.startswith(("0o", "0b")):
55        # Leave octal and binary literals alone.
56        pass
57    elif text.startswith("0x"):
58        text = format_hex(text)
59    elif "e" in text:
60        text = format_scientific_notation(text)
61    elif text.endswith(("j", "l")):
62        text = format_long_or_complex_number(text)
63    else:
64        text = format_float_or_int_string(text)
65    leaf.value = text
66