From b56f3c803573973fa8d754356ba7f074661aea46 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Fri, 29 Nov 2024 16:18:23 +0100 Subject: [PATCH] Fix standard_value_replacements() for hexadecimal numbers (cf #24) --- src/litgen/internal/cpp_to_python.py | 25 +++---- .../tests/internal/cpp_to_python_test.py | 68 ++++++++++++++++--- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/litgen/internal/cpp_to_python.py b/src/litgen/internal/cpp_to_python.py index 2bc57625..bfac1025 100644 --- a/src/litgen/internal/cpp_to_python.py +++ b/src/litgen/internal/cpp_to_python.py @@ -721,23 +721,16 @@ def standard_type_replacements() -> RegexReplacementList: def standard_value_replacements() -> RegexReplacementList: - """Replacements for C++ code when translating to python. - - Consists mostly of - * number translation (e.g. `1.5f` -> `1.5`) - """ + """Replacements for C++ code when translating to Python.""" replacements_str = r""" - \btrue\b -> True \bfalse\b -> False \bvoid\s*\* -> Any \bvoid\b -> None \bNULL\b -> None \bnullptr\b -> None - \std::nullopt\b -> None - ^std::nullopt\b$ -> None - \std.nullopt\b -> None - ^std.nullopt\b$ -> None + \bstd::nullopt\b -> None + \bstd.nullopt\b -> None \bstd::string\(\) -> "" \bstd.string\(\) -> "" @@ -749,14 +742,14 @@ def standard_value_replacements() -> RegexReplacementList: \bLDBL_MIN\b -> sys.float_info.min \bLDBL_MAX\b -> sys.float_info.max - - ([+-]?[0-9]+([.][0-9]*)?|[.][0-9]+)(d?) -> \1 - ([+-]?[0-9]+([.][0-9]*)?|[.][0-9]+)(f?) -> \1 - + ([0-9])'([0-9]) -> \1_\2 + (? \1 :: -> . """ - # Note: the two last regexes replace C numbers like 1.5f or 1.5d by 1.5 - + # Explanation of the last regexes: + # ([0-9])'([0-9]) -> \1_\2 # Replace 1'000 by 1_000 + # (? \1 + # Replace C numbers like 1.5f or 1.5d by 1.5 replaces = RegexReplacementList.from_string(replacements_str) return replaces diff --git a/src/litgen/tests/internal/cpp_to_python_test.py b/src/litgen/tests/internal/cpp_to_python_test.py index 5d430c2d..b7fa6243 100644 --- a/src/litgen/tests/internal/cpp_to_python_test.py +++ b/src/litgen/tests/internal/cpp_to_python_test.py @@ -3,19 +3,71 @@ from litgen.internal import cpp_to_python -def test_standard_replacements(): +def test_opencv_replacements(): s = "cv::Sizeounette cv::Size s = cv::Size()" r = litgen.opencv_replacements().apply(s) assert r == "cv::Sizeounette Size s = (0, 0)" - s = "a = 1.5f;" - r = litgen.opencv_replacements().apply(s) - r = litgen.standard_value_replacements().apply(s) - assert r == "a = 1.5;" - s = "a = -1.5d;" - r = litgen.standard_value_replacements().apply(s) - assert r == "a = -1.5;" +def test_standard_replacements(): + replacements = litgen.standard_value_replacements() + + # Basic float replacements + assert replacements.apply("a = 1.5f;") == "a = 1.5;" + assert replacements.apply("a = -1.5d;") == "a = -1.5;" + assert replacements.apply("a = 2.0;") == "a = 2.0;" + + # Scientific notation + assert replacements.apply("a = 1.5e10f;") == "a = 1.5e10;" + assert replacements.apply("a = -1.5E-3d;") == "a = -1.5E-3;" + assert replacements.apply("a = .5e2;") == "a = .5e2;" + assert replacements.apply("a = -1E+2f;") == "a = -1E+2;" + + # Hexadecimal literals + assert replacements.apply("a = 0x7000000e;" ) == "a = 0x7000000e;" + assert replacements.apply("a = 0x7000000f;" ) == "a = 0x7000000f;" + assert replacements.apply("a = 0XABCD;" ) == "a = 0XABCD;" + + # Octal literals + assert replacements.apply("a = 0755;" ) == "a = 0755;" # Classic octal + assert replacements.apply("a = 0o755;" ) == "a = 0o755;" # Modern octal + + # Binary literals + assert replacements.apply("a = 0b1010;" ) == "a = 0b1010;" + assert replacements.apply("a = 0B1010;" ) == "a = 0B1010;" + + # True/false replacements + assert replacements.apply("flag = true;") == "flag = True;" + assert replacements.apply("flag = false;") == "flag = False;" + + # nullptr/nullopt/void replacements + assert replacements.apply("p = nullptr;") == "p = None;" + assert replacements.apply("opt = std::nullopt;") == "opt = None;" + assert replacements.apply("auto value = void*();") == "auto value = Any();" + + # String replacements + assert replacements.apply("s = std::string();") == 's = "";' + + # Macros + assert replacements.apply("min = FLT_MIN; max = FLT_MAX;") == ( + "min = sys.float_info.min; max = sys.float_info.max;" + ) + + # Large integers + assert replacements.apply("a = 0xFFFFFFFF;") == "a = 0xFFFFFFFF;" + assert replacements.apply("a = 12345678901234567890;") == "a = 12345678901234567890;" + + # Numbers with underscores + assert replacements.apply("a = 1'000'000;") == "a = 1_000_000;" + + # Numbers with single quotes -> Converted to underscores + assert replacements.apply("a = 1'000'000;") == "a = 1_000_000;" + assert replacements.apply("a = -1'234'567;") == "a = -1_234_567;" + assert replacements.apply("a = 1'2'3'4;") == "a = 1_2_3_4;" + + # Verify valid Python syntax is preserved + assert replacements.apply("a = 1_000_000;") == "a = 1_000_000;" + assert replacements.apply("a = -1_234_567;") == "a = -1_234_567;" def test_std_array():