tpy-lang 0.3.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tpy_lang-0.3.0.dev0.dist-info/METADATA +151 -0
- tpy_lang-0.3.0.dev0.dist-info/RECORD +333 -0
- tpy_lang-0.3.0.dev0.dist-info/WHEEL +4 -0
- tpy_lang-0.3.0.dev0.dist-info/entry_points.txt +3 -0
- tpyc/__init__.py +104 -0
- tpyc/__main__.py +6 -0
- tpyc/_buildinfo.py +1 -0
- tpyc/_data/docs/LANGUAGE_FEATURES.md +6278 -0
- tpyc/_data/docs/STDLIB_ROADMAP.md +1258 -0
- tpyc/_data/docs/TPY_FOR_AGENTS.md +556 -0
- tpyc/_data/lib/tpy/_bindings/__init__.py +6 -0
- tpyc/_data/lib/tpy/_bindings/pcre2.py +173 -0
- tpyc/_data/lib/tpy/_bindings/posix_socket.py +161 -0
- tpyc/_data/lib/tpy/_functools_macros.py +80 -0
- tpyc/_data/lib/tpy/_macro_helpers.py +161 -0
- tpyc/_data/lib/tpy/argparse.py +2062 -0
- tpyc/_data/lib/tpy/asyncio/__init__.py +744 -0
- tpyc/_data/lib/tpy/asyncio/_executor.py +515 -0
- tpyc/_data/lib/tpy/base64.py +410 -0
- tpyc/_data/lib/tpy/bisect.py +39 -0
- tpyc/_data/lib/tpy/builtins.py +38 -0
- tpyc/_data/lib/tpy/dataclasses.py +354 -0
- tpyc/_data/lib/tpy/enum.py +23 -0
- tpyc/_data/lib/tpy/functools.py +33 -0
- tpyc/_data/lib/tpy/hashlib.py +206 -0
- tpyc/_data/lib/tpy/heapq.py +118 -0
- tpyc/_data/lib/tpy/io.py +395 -0
- tpyc/_data/lib/tpy/json.py +221 -0
- tpyc/_data/lib/tpy/math.py +406 -0
- tpyc/_data/lib/tpy/random.py +597 -0
- tpyc/_data/lib/tpy/re.py +467 -0
- tpyc/_data/lib/tpy/socket.py +379 -0
- tpyc/_data/lib/tpy/struct.py +178 -0
- tpyc/_data/lib/tpy/sys.py +40 -0
- tpyc/_data/lib/tpy/time.py +39 -0
- tpyc/_data/lib/tpy/tpy/__init__.py +78 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/__init__.py +10 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_decorators.py +37 -0
- tpyc/_data/lib/tpy/tpy/_bootstrap/_extern.py +64 -0
- tpyc/_data/lib/tpy/tpy/_builtins/__init__.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_bytes.py +378 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_dict.py +151 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_exceptions.py +125 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_funcs.py +681 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_io.py +97 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_list.py +127 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_range.py +52 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_set.py +139 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_super.py +11 -0
- tpyc/_data/lib/tpy/tpy/_builtins/_types.py +661 -0
- tpyc/_data/lib/tpy/tpy/_core/__init__.py +23 -0
- tpyc/_data/lib/tpy/tpy/_core/_bytes_view.py +129 -0
- tpyc/_data/lib/tpy/tpy/_core/_containers.py +137 -0
- tpyc/_data/lib/tpy/tpy/_core/_functions.py +40 -0
- tpyc/_data/lib/tpy/tpy/_core/_types.py +2061 -0
- tpyc/_data/lib/tpy/tpy/_typing/__init__.py +77 -0
- tpyc/_data/lib/tpy/tpy/_version.py +29 -0
- tpyc/_data/lib/tpy/tpy/bits.py +28 -0
- tpyc/_data/lib/tpy/tpy/coro/__init__.py +127 -0
- tpyc/_data/lib/tpy/tpy/extern.py +8 -0
- tpyc/_data/lib/tpy/tpy/mem.py +49 -0
- tpyc/_data/lib/tpy/tpy/unsafe.py +195 -0
- tpyc/_data/lib/tpy/tpy/version.py +21 -0
- tpyc/_data/lib/tpy/typing.py +13 -0
- tpyc/_data/runtime/cpp/include/tpy/any.hpp +461 -0
- tpyc/_data/runtime/cpp/include/tpy/as_ostream.hpp +117 -0
- tpyc/_data/runtime/cpp/include/tpy/async.hpp +76 -0
- tpyc/_data/runtime/cpp/include/tpy/bigint.hpp +1343 -0
- tpyc/_data/runtime/cpp/include/tpy/builtins.hpp +400 -0
- tpyc/_data/runtime/cpp/include/tpy/bytes_ops.hpp +469 -0
- tpyc/_data/runtime/cpp/include/tpy/container_ops.hpp +487 -0
- tpyc/_data/runtime/cpp/include/tpy/copy_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/core.hpp +558 -0
- tpyc/_data/runtime/cpp/include/tpy/dict_ops.hpp +289 -0
- tpyc/_data/runtime/cpp/include/tpy/dunder.hpp +750 -0
- tpyc/_data/runtime/cpp/include/tpy/dynamic.hpp +44 -0
- tpyc/_data/runtime/cpp/include/tpy/enum.hpp +40 -0
- tpyc/_data/runtime/cpp/include/tpy/file.hpp +245 -0
- tpyc/_data/runtime/cpp/include/tpy/fixed_int.hpp +317 -0
- tpyc/_data/runtime/cpp/include/tpy/format.hpp +954 -0
- tpyc/_data/runtime/cpp/include/tpy/frame_slot.hpp +120 -0
- tpyc/_data/runtime/cpp/include/tpy/generator.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/iterable_ops.hpp +122 -0
- tpyc/_data/runtime/cpp/include/tpy/itertools.hpp +749 -0
- tpyc/_data/runtime/cpp/include/tpy/next_iter.hpp +82 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_map.hpp +518 -0
- tpyc/_data/runtime/cpp/include/tpy/ordered_set.hpp +337 -0
- tpyc/_data/runtime/cpp/include/tpy/own_iter.hpp +54 -0
- tpyc/_data/runtime/cpp/include/tpy/pascal_graph_sdl.hpp +192 -0
- tpyc/_data/runtime/cpp/include/tpy/printing.hpp +302 -0
- tpyc/_data/runtime/cpp/include/tpy/protocols.hpp +61 -0
- tpyc/_data/runtime/cpp/include/tpy/range.hpp +115 -0
- tpyc/_data/runtime/cpp/include/tpy/ranges.hpp +212 -0
- tpyc/_data/runtime/cpp/include/tpy/set_ops.hpp +265 -0
- tpyc/_data/runtime/cpp/include/tpy/slice.hpp +47 -0
- tpyc/_data/runtime/cpp/include/tpy/span_iter.hpp +42 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/math.hpp +41 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/pcre2_h.hpp +96 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/random.hpp +25 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/socket_h.hpp +145 -0
- tpyc/_data/runtime/cpp/include/tpy/stdlib/time.hpp +62 -0
- tpyc/_data/runtime/cpp/include/tpy/system.hpp +121 -0
- tpyc/_data/runtime/cpp/include/tpy/throwable.hpp +55 -0
- tpyc/_data/runtime/cpp/include/tpy/tpy.hpp +156 -0
- tpyc/_data/runtime/cpp/include/tpy/type_name.hpp +77 -0
- tpyc/_data/runtime/cpp/include/tpy/type_traits.hpp +240 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_array_storage.hpp +250 -0
- tpyc/_data/runtime/cpp/include/tpy/uninit_heap_storage.hpp +277 -0
- tpyc/_data/runtime/cpp/include/tpy/varargs.hpp +174 -0
- tpyc/_data/runtime/cpp/include/tpy/variant_ref.hpp +118 -0
- tpyc/_data/runtime/cpp/src/stdlib/socket_impl.cpp +104 -0
- tpyc/_data/runtime/cpp/third_party/README.md +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/AUTHORS +36 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/CMakeLists.txt +1233 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/COPYING +5 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/ChangeLog +3097 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/HACKING +853 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/INSTALL +368 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/LICENCE +94 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NEWS +492 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/NON-AUTOTOOLS-BUILD +430 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/README +956 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/COPYING-CMAKE-SCRIPTS +22 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindEditline.cmake +16 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindPackageHandleStandardArgs.cmake +58 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/FindReadline.cmake +29 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config-version.cmake.in +15 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/cmake/pcre2-config.cmake.in +148 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/config-cmake.h.in +56 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-16.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-32.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-8.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/libpcre2-posix.pc.in +13 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/pcre2-config.in +121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.generic +483 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/config.h.in +460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.generic +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2.h.in +1010 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_auto_possess.c +1371 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chartables.c.dist +196 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_chkdint.c +96 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_compile.c +11001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_config.c +252 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_context.c +510 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_convert.c +1189 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dfa_match.c +4119 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_dftables.c +297 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_error.c +345 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_extuni.c +162 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_find_bracket.c +219 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_fuzzsupport.c +792 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_internal.h +2084 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_intmodedep.h +940 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_compile.c +14972 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_match.c +200 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_misc.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_neon_inc.h +354 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_simd_inc.h +2355 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_jit_test.c +2528 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_maketables.c +165 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match.c +7777 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_match_data.c +185 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_newline.c +243 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ord2utf.c +120 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_pattern_info.c +432 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_printint.c +886 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_script_run.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_serialize.c +286 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_string_utils.c +237 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_study.c +1915 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substitute.c +1009 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_substring.c +550 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_tables.c +234 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucd.c +5460 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucp.h +396 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_ucptables.c +1533 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_valid_utf.c +398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2_xclass.c +308 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2demo.c +497 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2grep.c +4606 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.c +425 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix.h +187 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2posix_test.c +209 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/pcre2test.c +9708 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c +137 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c +327 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c +89 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c +62 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c +40 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c +72 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c +172 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c +141 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c +102 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfig.h +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigCPU.h +188 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitConfigInternal.h +907 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.c +3561 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitLir.h +2466 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_32.c +4636 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_64.c +3491 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeARM_T2_32.c +4302 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeLOONGARCH_64.c +3765 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_32.c +472 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_64.c +387 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeMIPS_common.c +4259 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_32.c +485 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_64.c +719 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativePPC_common.c +3161 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_32.c +142 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_64.c +222 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeRISCV_common.c +3121 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeS390X.c +4526 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_32.c +1685 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_64.c +1398 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitNativeX86_common.c +5001 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitSerialize.c +516 -0
- tpyc/_data/runtime/cpp/third_party/pcre2/src/sljit/sljitUtils.c +344 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.sources.txt +54 -0
- tpyc/_data/runtime/cpp/third_party/pcre2.vendor.json +7 -0
- tpyc/build/__init__.py +7 -0
- tpyc/build/pcre2.py +122 -0
- tpyc/build/third_party.py +413 -0
- tpyc/cli.py +822 -0
- tpyc/codegen_cpp/__init__.py +18 -0
- tpyc/codegen_cpp/builtins.py +484 -0
- tpyc/codegen_cpp/context.py +2064 -0
- tpyc/codegen_cpp/expressions.py +5940 -0
- tpyc/codegen_cpp/functions.py +1913 -0
- tpyc/codegen_cpp/gen_async.py +3258 -0
- tpyc/codegen_cpp/gen_generators.py +657 -0
- tpyc/codegen_cpp/generator.py +2258 -0
- tpyc/codegen_cpp/match.py +1997 -0
- tpyc/codegen_cpp/param_const.py +172 -0
- tpyc/codegen_cpp/protocols.py +907 -0
- tpyc/codegen_cpp/records.py +1654 -0
- tpyc/codegen_cpp/resumable_cfg.py +1651 -0
- tpyc/codegen_cpp/statements.py +4963 -0
- tpyc/codegen_cpp/string_dispatch.py +76 -0
- tpyc/codegen_cpp/test_context.py +46 -0
- tpyc/codegen_cpp/test_param_const.py +113 -0
- tpyc/codegen_cpp/test_resumable_cfg.py +182 -0
- tpyc/codegen_cpp/type_resolution.py +53 -0
- tpyc/codegen_cpp/types.py +436 -0
- tpyc/codegen_cpp/variant_access.py +135 -0
- tpyc/coercions.py +749 -0
- tpyc/compilation_context.py +57 -0
- tpyc/compiler.py +3945 -0
- tpyc/cycle_detection.py +358 -0
- tpyc/diagnostics.py +135 -0
- tpyc/dump_types.py +353 -0
- tpyc/frontend_diagnostics.py +47 -0
- tpyc/frontend_ir/__init__.py +140 -0
- tpyc/frontend_ir/lower.py +1098 -0
- tpyc/frontend_ir/nodes.py +718 -0
- tpyc/frontend_ir/resolver_adapter.py +151 -0
- tpyc/frontend_plugin.py +209 -0
- tpyc/install_docs.py +81 -0
- tpyc/liveness.py +756 -0
- tpyc/macro_api.py +1724 -0
- tpyc/macro_loader.py +497 -0
- tpyc/module_names.py +64 -0
- tpyc/modules/__init__.py +31 -0
- tpyc/modules/defs.py +89 -0
- tpyc/modules/registry.py +36 -0
- tpyc/modules/resolver.py +192 -0
- tpyc/modules/type_resolution.py +629 -0
- tpyc/namespace.py +172 -0
- tpyc/parse/__init__.py +84 -0
- tpyc/parse/imports.py +490 -0
- tpyc/parse/nodes.py +1732 -0
- tpyc/parse/parser.py +4043 -0
- tpyc/parse/resolve_refs.py +466 -0
- tpyc/parse/type_resolver.py +1060 -0
- tpyc/prescan.py +254 -0
- tpyc/qnames.py +149 -0
- tpyc/repl.py +529 -0
- tpyc/repl_backends.py +848 -0
- tpyc/sema/__init__.py +21 -0
- tpyc/sema/analyzer.py +3625 -0
- tpyc/sema/bound_check.py +72 -0
- tpyc/sema/builder_trace.py +684 -0
- tpyc/sema/calls.py +5406 -0
- tpyc/sema/compatibility.py +2107 -0
- tpyc/sema/context.py +1243 -0
- tpyc/sema/expressions.py +3737 -0
- tpyc/sema/flow_facts.py +199 -0
- tpyc/sema/init_tracker.py +150 -0
- tpyc/sema/list_literals.py +69 -0
- tpyc/sema/literal_utils.py +27 -0
- tpyc/sema/local_deduction.py +1088 -0
- tpyc/sema/macros.py +179 -0
- tpyc/sema/match.py +1177 -0
- tpyc/sema/method_expansion.py +347 -0
- tpyc/sema/methods.py +2197 -0
- tpyc/sema/mutation_propagation.py +268 -0
- tpyc/sema/narrowing.py +857 -0
- tpyc/sema/numeric_lattice.py +160 -0
- tpyc/sema/operators.py +402 -0
- tpyc/sema/overloads.py +841 -0
- tpyc/sema/protocols.py +1209 -0
- tpyc/sema/reach_analysis.py +202 -0
- tpyc/sema/registration.py +3156 -0
- tpyc/sema/scope_tracker.py +193 -0
- tpyc/sema/statements.py +4426 -0
- tpyc/sema/type_ops.py +1879 -0
- tpyc/sema/value_range.py +181 -0
- tpyc/symbol_binding.py +259 -0
- tpyc/test_c3_mro.py +208 -0
- tpyc/test_cli_argv.py +52 -0
- tpyc/test_compiler.py +559 -0
- tpyc/test_contains_type_param.py +101 -0
- tpyc/test_cycle_detection.py +221 -0
- tpyc/test_dump_types.py +225 -0
- tpyc/test_install_docs.py +65 -0
- tpyc/test_local_cpp_form.py +135 -0
- tpyc/test_macro_loader.py +76 -0
- tpyc/test_method_expansion.py +254 -0
- tpyc/test_nominal_identity.py +182 -0
- tpyc/test_overloads.py +410 -0
- tpyc/test_parse.py +303 -0
- tpyc/test_parse_type_ref.py +506 -0
- tpyc/test_parse_version_info.py +58 -0
- tpyc/test_reach_analysis.py +72 -0
- tpyc/test_ref_type.py +216 -0
- tpyc/test_send_sync_substitution.py +276 -0
- tpyc/test_tuple_mutation_propagation.py +206 -0
- tpyc/test_type_def_registry.py +1729 -0
- tpyc/test_union_types.py +195 -0
- tpyc/type_def_registry.py +975 -0
- tpyc/typesys.py +5104 -0
tpyc/_data/lib/tpy/re.py
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# tpy: cpp_namespace("tpystd::re")
|
|
2
|
+
"""Regular expressions, CPython-compatible surface, backed by PCRE2.
|
|
3
|
+
|
|
4
|
+
Architecture:
|
|
5
|
+
* `_bindings.pcre2` -- raw @native bindings to the PCRE2 C API.
|
|
6
|
+
* this module -- pure-TPy facade. Pattern / Match classes manage PCRE2
|
|
7
|
+
handle lifetimes via __del__. All Python semantics (flag mapping, group
|
|
8
|
+
accessors, sub/split logic, error model) live here, not in C++.
|
|
9
|
+
|
|
10
|
+
Slice 1 surface:
|
|
11
|
+
* compile(), search(), match(), fullmatch(), findall(), sub(), split()
|
|
12
|
+
* Pattern + Match classes with the methods above.
|
|
13
|
+
* Flags: IGNORECASE, MULTILINE, DOTALL, VERBOSE, ASCII (CPython bit values).
|
|
14
|
+
* `re.error` exception, raised on invalid patterns.
|
|
15
|
+
|
|
16
|
+
TODO(v2): items deferred to a follow-up slice -- each is independent:
|
|
17
|
+
* `re.compile` cache. Needs module-level mutable state (see
|
|
18
|
+
STDLIB_ROADMAP "stdlib-enablement workstream"). Until then,
|
|
19
|
+
`re.search("...", s)` in a hot loop is slower than caching a Pattern.
|
|
20
|
+
* Named-group accessors: `match.group("name")` / `match.groupdict()`.
|
|
21
|
+
Needs PCRE2 nametable walk + named-group index lookup.
|
|
22
|
+
* finditer as a true generator (currently returns list[Own[Match]]).
|
|
23
|
+
Loses streaming; minor for typical use, real for huge subjects.
|
|
24
|
+
* bytes input on the public API (today: str only). Pattern + Match
|
|
25
|
+
accept str; PCRE2 internally takes uint8_t* + length, so the lower
|
|
26
|
+
layer is bytes-ready.
|
|
27
|
+
* Python -> PCRE2 syntax translator. Not required for the current
|
|
28
|
+
surface (PCRE2 accepts Python's `(?P<name>...)` form natively for
|
|
29
|
+
back-compat). Add when we hit a real divergence -- candidates:
|
|
30
|
+
`\1`-style backrefs in `sub` replacements, `(?#comment)` syntax,
|
|
31
|
+
a few Unicode property edge cases.
|
|
32
|
+
* `count` arg on `Pattern.sub` / module-level `sub` (limit number of
|
|
33
|
+
replacements). Naive impl: walk finditer + manual splice; cleaner:
|
|
34
|
+
a single `pcre2_substitute` call in non-global mode, looped.
|
|
35
|
+
* `Match.span` / `start` / `end` returning `int` (BigInt) instead of
|
|
36
|
+
`Int32` to match CPython exactly. Today they return `Int32` -- in
|
|
37
|
+
practice tuple printing happens to match CPython, but type inference
|
|
38
|
+
for downstream code differs (e.g. arithmetic on Match.start() picks
|
|
39
|
+
Int32 ops vs CPython's int).
|
|
40
|
+
* `Pattern.__repr__` / `Match.__repr__` matching CPython's format
|
|
41
|
+
(`re.compile('...')` / `<re.Match object; span=(a, b), match='...'>`).
|
|
42
|
+
Blocked on a Python-style `repr(str)` helper (escape backslashes,
|
|
43
|
+
quotes, non-printables) and a flag-bits-to-name decoder. Land together
|
|
44
|
+
to avoid asymmetric support.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
from typing import Final, Optional
|
|
49
|
+
from tpy import (
|
|
50
|
+
Int32, UInt8, UInt32, UInt64, Ptr, readonly, Own, String, nocopy,
|
|
51
|
+
)
|
|
52
|
+
from tpy.extern import cpp_template
|
|
53
|
+
from tpy.mem import UninitArrayStorage, UninitHeapStorage
|
|
54
|
+
from tpy.unsafe import unsafe_ptr, unsafe_cast, unsafe_load, unsafe_str_from_buf
|
|
55
|
+
from tpy import take_ptr
|
|
56
|
+
|
|
57
|
+
# Bare `0`/`1` flow through to `size_t` / `uint32_t` PCRE2 args because the
|
|
58
|
+
# compiler treats integer literals (and literal-seeded locals like
|
|
59
|
+
# `offset = 0`) as polymorphic enough to retro-fit unsigned targets when
|
|
60
|
+
# the value provably fits. The remaining `UInt64(...)` / `UInt32(...)`
|
|
61
|
+
# casts in this file are on `len(...)` results (BigInt) and other typed
|
|
62
|
+
# sources, where a runtime narrowing check is intentional.
|
|
63
|
+
from _bindings import pcre2
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ---------- RAII wrappers for PCRE2 handles ----------
|
|
67
|
+
# Every handle is wrapped in an @nocopy owning type so the corresponding
|
|
68
|
+
# free runs automatically on scope exit (returns, raises, field-holding
|
|
69
|
+
# record destruction). All three free functions are null-safe, so __del__
|
|
70
|
+
# needs no null check.
|
|
71
|
+
#
|
|
72
|
+
# @nocopy+__del__ wrappers have their auto default ctor suppressed, so
|
|
73
|
+
# the enclosing record's field init must MIL-hoist (RHS references only
|
|
74
|
+
# ctor params / module-level names, no body-locals). That's why _OwnedCode
|
|
75
|
+
# takes high-level args in __init__ and delegates the multi-step PCRE2
|
|
76
|
+
# call sequence to a staticmethod returning Ptr[pcre2.Code] -- the
|
|
77
|
+
# dangling-return check trusts locals bound from call returns.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@nocopy
|
|
81
|
+
class _OwnedMatchData:
|
|
82
|
+
_p: Ptr[pcre2.MatchData]
|
|
83
|
+
def __init__(self, p: Ptr[pcre2.MatchData]) -> None:
|
|
84
|
+
self._p = p
|
|
85
|
+
def __del__(self) -> None:
|
|
86
|
+
pcre2.match_data_free(self._p)
|
|
87
|
+
def get(self) -> Ptr[pcre2.MatchData]:
|
|
88
|
+
return self._p
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------- re.error exception ----------
|
|
92
|
+
# Must be defined BEFORE _OwnedCode because its _compile staticmethod is
|
|
93
|
+
# emitted inline in the generated header and throws `error`, which
|
|
94
|
+
# requires a complete type at the throw site (not just a forward decl).
|
|
95
|
+
class error(Exception):
|
|
96
|
+
"""Raised when PCRE2 rejects a pattern at compile time, or hits a
|
|
97
|
+
match-time error (rare). Catchable as a normal exception.
|
|
98
|
+
|
|
99
|
+
Caller-side gap that still bites: `except re.error:` is blocked by
|
|
100
|
+
the qualified-except-clause limitation (BUGS.md). Users today
|
|
101
|
+
must `from re import error` (no alias) then `except error:`.
|
|
102
|
+
"""
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Convert a PCRE2 negative error code into a human-readable message via
|
|
107
|
+
# pcre2_get_error_message. Buffer is stack-allocated 256 bytes via
|
|
108
|
+
# UninitArrayStorage -- RAII, no manual free.
|
|
109
|
+
def _pcre2_error_msg(errcode: Int32) -> str:
|
|
110
|
+
buf = UninitArrayStorage[UInt8, 256]()
|
|
111
|
+
n = pcre2.get_error_message(errcode, buf.ptr(), 256)
|
|
112
|
+
if n < 0:
|
|
113
|
+
return "unknown error"
|
|
114
|
+
return unsafe_str_from_buf(unsafe_cast(buf.ptr()), UInt64(n))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@nocopy
|
|
118
|
+
class _OwnedCode:
|
|
119
|
+
_p: Ptr[pcre2.Code]
|
|
120
|
+
def __init__(self, pattern: str, flags: Int32) -> None:
|
|
121
|
+
self._p = _OwnedCode._compile(pattern, flags)
|
|
122
|
+
def __del__(self) -> None:
|
|
123
|
+
pcre2.code_free(self._p)
|
|
124
|
+
def get(self) -> Ptr[pcre2.Code]:
|
|
125
|
+
return self._p
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def _compile(pattern: str, flags: Int32) -> Ptr[pcre2.Code]:
|
|
129
|
+
errcode: Int32 = 0
|
|
130
|
+
erroff: UInt64 = 0
|
|
131
|
+
opts = _to_pcre2_opts(flags)
|
|
132
|
+
p_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(pattern))
|
|
133
|
+
code = pcre2.compile(p_data, UInt64(len(pattern)),
|
|
134
|
+
opts, take_ptr(errcode), take_ptr(erroff),
|
|
135
|
+
None)
|
|
136
|
+
if code is None:
|
|
137
|
+
msg = _pcre2_error_msg(errcode)
|
|
138
|
+
raise error(f"compile error at offset {erroff}: {msg}")
|
|
139
|
+
return code
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@nocopy
|
|
143
|
+
class _OwnedMatchContext:
|
|
144
|
+
_p: Ptr[pcre2.MatchContext]
|
|
145
|
+
def __init__(self) -> None:
|
|
146
|
+
self._p = pcre2.match_context_create(None)
|
|
147
|
+
def __del__(self) -> None:
|
|
148
|
+
pcre2.match_context_free(self._p)
|
|
149
|
+
def get(self) -> Ptr[pcre2.MatchContext]:
|
|
150
|
+
return self._p
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# ---------- Public flag constants (CPython-compatible bit values) ----------
|
|
154
|
+
|
|
155
|
+
# User-facing flags are `Int32`: the total bit surface is tiny (max 256),
|
|
156
|
+
# negative values are never valid, and Int32 is TPy's DefaultInt so users
|
|
157
|
+
# don't need to write `UInt32(...)` when mixing flags with bare literals.
|
|
158
|
+
# Internally `_to_pcre2_opts` translates to PCRE2's `UInt32` flag space
|
|
159
|
+
# where top-bit values like pcre2.PCRE2_ANCHORED require the wider unsigned range.
|
|
160
|
+
NOFLAG: Final[Int32] = 0
|
|
161
|
+
IGNORECASE: Final[Int32] = 2
|
|
162
|
+
MULTILINE: Final[Int32] = 8
|
|
163
|
+
DOTALL: Final[Int32] = 16
|
|
164
|
+
VERBOSE: Final[Int32] = 64
|
|
165
|
+
ASCII: Final[Int32] = 256
|
|
166
|
+
|
|
167
|
+
# Short aliases (CPython exposes both forms).
|
|
168
|
+
I: Final[Int32] = IGNORECASE
|
|
169
|
+
M: Final[Int32] = MULTILINE
|
|
170
|
+
S: Final[Int32] = DOTALL
|
|
171
|
+
X: Final[Int32] = VERBOSE
|
|
172
|
+
A: Final[Int32] = ASCII
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _to_pcre2_opts(flags: Int32) -> UInt32:
|
|
176
|
+
"""Translate `re.*` flag bits to PCRE2 option bits.
|
|
177
|
+
|
|
178
|
+
UTF + UCP are on by default (matches CPython str-mode regex behavior:
|
|
179
|
+
Unicode-aware \\d, \\w, \\s, case-folding). `re.ASCII` opts out.
|
|
180
|
+
"""
|
|
181
|
+
opts: UInt32 = pcre2.PCRE2_UTF | pcre2.PCRE2_UCP
|
|
182
|
+
if (flags & IGNORECASE) != 0:
|
|
183
|
+
opts |= pcre2.PCRE2_CASELESS
|
|
184
|
+
if (flags & MULTILINE) != 0:
|
|
185
|
+
opts |= pcre2.PCRE2_MULTILINE
|
|
186
|
+
if (flags & DOTALL) != 0:
|
|
187
|
+
opts |= pcre2.PCRE2_DOTALL
|
|
188
|
+
if (flags & VERBOSE) != 0:
|
|
189
|
+
opts |= pcre2.PCRE2_EXTENDED
|
|
190
|
+
if (flags & ASCII) != 0:
|
|
191
|
+
opts &= ~(pcre2.PCRE2_UTF | pcre2.PCRE2_UCP)
|
|
192
|
+
return opts
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# ---------- Match ----------
|
|
196
|
+
|
|
197
|
+
class Match:
|
|
198
|
+
"""Result of a successful match. Owns its PCRE2 match-data block (via
|
|
199
|
+
the `_OwnedMatchData` wrapper -- freed automatically on destruction)
|
|
200
|
+
and a copy of the subject string (so group() can return slices that
|
|
201
|
+
outlive the originating user variable)."""
|
|
202
|
+
|
|
203
|
+
_md: _OwnedMatchData
|
|
204
|
+
_subject: str
|
|
205
|
+
_ngroups: Int32 # number of populated entries in the ovector
|
|
206
|
+
|
|
207
|
+
def __init__(self, md: Own[_OwnedMatchData], subject: str,
|
|
208
|
+
ngroups: Int32) -> None:
|
|
209
|
+
self._md = md
|
|
210
|
+
self._subject = subject
|
|
211
|
+
self._ngroups = ngroups
|
|
212
|
+
|
|
213
|
+
def _ovec_load(self, i: UInt32) -> UInt64:
|
|
214
|
+
ovec = pcre2.get_ovector_pointer(self._md.get())
|
|
215
|
+
return unsafe_load(ovec, i)
|
|
216
|
+
|
|
217
|
+
def span(self, group: Int32 = 0) -> tuple[Int32, Int32]:
|
|
218
|
+
"""(start, end) byte offsets of `group` in the subject. (-1, -1)
|
|
219
|
+
means the group did not participate.
|
|
220
|
+
|
|
221
|
+
TODO(v2): non-participating group should surface as `(-1, -1)` to
|
|
222
|
+
match CPython; today returns `(0, 0)`. Trivial to fix once the
|
|
223
|
+
Match accessor APIs commit to either Int32 or BigInt return type
|
|
224
|
+
(-1 needs a signed type)."""
|
|
225
|
+
if group < 0 or group >= self._ngroups:
|
|
226
|
+
raise error(f"no such group: {group}")
|
|
227
|
+
start = self._ovec_load(UInt32.trunc(group * 2))
|
|
228
|
+
end = self._ovec_load(UInt32.trunc(group * 2 + 1))
|
|
229
|
+
if start == pcre2.PCRE2_UNSET or end == pcre2.PCRE2_UNSET:
|
|
230
|
+
return (0, 0)
|
|
231
|
+
return (Int32.trunc(start), Int32.trunc(end))
|
|
232
|
+
|
|
233
|
+
def start(self, group: Int32 = 0) -> Int32:
|
|
234
|
+
return self.span(group)[0]
|
|
235
|
+
|
|
236
|
+
def end(self, group: Int32 = 0) -> Int32:
|
|
237
|
+
return self.span(group)[1]
|
|
238
|
+
|
|
239
|
+
def group(self, i: Int32 = 0) -> str:
|
|
240
|
+
"""Substring of the subject for `group` (0 = full match)."""
|
|
241
|
+
s, e = self.span(i)
|
|
242
|
+
return self._subject[s:e]
|
|
243
|
+
|
|
244
|
+
def groups(self) -> Own[list[str]]:
|
|
245
|
+
"""All capture groups as a list (excluding group 0).
|
|
246
|
+
|
|
247
|
+
TODO(v2): return `tuple[str, ...]` to match CPython instead of
|
|
248
|
+
list. Blocked on varadic-tuple support in TPy."""
|
|
249
|
+
out: list[str] = []
|
|
250
|
+
for i in range(1, self._ngroups):
|
|
251
|
+
out.append(self.group(i))
|
|
252
|
+
return out
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# ---------- Pattern ----------
|
|
256
|
+
|
|
257
|
+
class Pattern:
|
|
258
|
+
"""Compiled regex. Holds the PCRE2 code + match-context handles; the
|
|
259
|
+
_OwnedCode / _OwnedMatchContext wrappers free them on destruction."""
|
|
260
|
+
|
|
261
|
+
_code: _OwnedCode
|
|
262
|
+
_mctx: _OwnedMatchContext
|
|
263
|
+
pattern: str
|
|
264
|
+
flags: Int32
|
|
265
|
+
|
|
266
|
+
def __init__(self, pattern: str, flags: Int32 = NOFLAG) -> None:
|
|
267
|
+
# Both field initializers reference only ctor params / module-level
|
|
268
|
+
# names -- no body-locals -- so they MIL-hoist into move-construction
|
|
269
|
+
# (safe on @nocopy+__del__ fields).
|
|
270
|
+
self._code = _OwnedCode(pattern, flags)
|
|
271
|
+
self._mctx = _OwnedMatchContext()
|
|
272
|
+
# JIT-compile for ~10x match speedup. Failure here is non-fatal --
|
|
273
|
+
# PCRE2 falls back to interpreted matching on patterns the JIT
|
|
274
|
+
# can't handle.
|
|
275
|
+
pcre2.jit_compile(self._code.get(), pcre2.PCRE2_JIT_COMPLETE)
|
|
276
|
+
self.pattern = pattern
|
|
277
|
+
self.flags = flags
|
|
278
|
+
|
|
279
|
+
def _do_match(self, subject: str, start_offset: UInt64,
|
|
280
|
+
opts: UInt32) -> Optional[Own[Match]]:
|
|
281
|
+
md_raw = pcre2.match_data_create_from_pattern(self._code.get(), None)
|
|
282
|
+
if md_raw is None:
|
|
283
|
+
raise error("out of memory allocating match data")
|
|
284
|
+
md = _OwnedMatchData(md_raw)
|
|
285
|
+
s_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(subject))
|
|
286
|
+
rc = pcre2.match(self._code.get(), s_data, UInt64(len(subject)),
|
|
287
|
+
start_offset, opts, md.get(), self._mctx.get())
|
|
288
|
+
if rc < 0:
|
|
289
|
+
if rc == pcre2.PCRE2_ERROR_NOMATCH:
|
|
290
|
+
return None # md drops here, frees automatically
|
|
291
|
+
raise error(_pcre2_error_msg(rc)) # same
|
|
292
|
+
return Match(md, subject, rc) # md moves into the Match
|
|
293
|
+
|
|
294
|
+
def search(self, subject: str) -> Optional[Own[Match]]:
|
|
295
|
+
return self._do_match(subject, 0, 0)
|
|
296
|
+
|
|
297
|
+
def match(self, subject: str) -> Optional[Own[Match]]:
|
|
298
|
+
return self._do_match(subject, 0, pcre2.PCRE2_ANCHORED)
|
|
299
|
+
|
|
300
|
+
def fullmatch(self, subject: str) -> Optional[Own[Match]]:
|
|
301
|
+
return self._do_match(subject, 0,
|
|
302
|
+
pcre2.PCRE2_ANCHORED | pcre2.PCRE2_ENDANCHORED)
|
|
303
|
+
|
|
304
|
+
def finditer(self, subject: str) -> Own[list[Match]]:
|
|
305
|
+
"""All non-overlapping matches as a list.
|
|
306
|
+
|
|
307
|
+
TODO(v2): return a true generator like CPython (lazy iteration).
|
|
308
|
+
Today materializes the full list -- fine for typical cases, real
|
|
309
|
+
memory cost on huge subjects."""
|
|
310
|
+
out: list[Match] = []
|
|
311
|
+
offset: UInt64 = 0
|
|
312
|
+
sub_len = UInt64(len(subject))
|
|
313
|
+
s_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(subject))
|
|
314
|
+
while offset <= sub_len:
|
|
315
|
+
md_raw = pcre2.match_data_create_from_pattern(self._code.get(), None)
|
|
316
|
+
if md_raw is None:
|
|
317
|
+
raise error("out of memory allocating match data")
|
|
318
|
+
md = _OwnedMatchData(md_raw)
|
|
319
|
+
rc = pcre2.match(self._code.get(), s_data, sub_len, offset,
|
|
320
|
+
0, md.get(), self._mctx.get())
|
|
321
|
+
if rc < 0:
|
|
322
|
+
if rc == pcre2.PCRE2_ERROR_NOMATCH:
|
|
323
|
+
break # md drops at end of iteration
|
|
324
|
+
raise error(_pcre2_error_msg(rc)) # md drops
|
|
325
|
+
ovec = pcre2.get_ovector_pointer(md.get())
|
|
326
|
+
mstart = unsafe_load(ovec, 0)
|
|
327
|
+
mend = unsafe_load(ovec, 1)
|
|
328
|
+
out.append(Match(md, subject, rc)) # md moves into Match
|
|
329
|
+
# Bump-along by one byte on zero-width match to avoid an
|
|
330
|
+
# infinite loop.
|
|
331
|
+
if mend == mstart:
|
|
332
|
+
offset = mend + 1
|
|
333
|
+
else:
|
|
334
|
+
offset = mend
|
|
335
|
+
return out
|
|
336
|
+
|
|
337
|
+
def findall(self, subject: str) -> Own[list[str]]:
|
|
338
|
+
"""All non-overlapping match strings (group 0).
|
|
339
|
+
|
|
340
|
+
TODO(v2): for patterns with capture groups, CPython returns a list
|
|
341
|
+
of capture-tuples (or single captures for one-group patterns), not
|
|
342
|
+
the whole-match string. Today we always return group(0) regardless
|
|
343
|
+
of pattern shape -- divergence flagged in `no_cpython.txt`."""
|
|
344
|
+
out: list[str] = []
|
|
345
|
+
# TODO(compiler): the natural form `for m in self.finditer(subject):`
|
|
346
|
+
# fails C++ compilation -- "cannot bind non-const lvalue reference
|
|
347
|
+
# to rvalue" -- because finditer returns `Own[list[Match]]`. See
|
|
348
|
+
# BUGS.md entry "Iterating directly over a call that returns
|
|
349
|
+
# Own[list[T]]". When the codegen fix lands (use `auto&&` for the
|
|
350
|
+
# iteration temp on rvalue iterables), drop the `matches` local.
|
|
351
|
+
matches = self.finditer(subject)
|
|
352
|
+
for m in matches:
|
|
353
|
+
out.append(m.group(Int32(0)))
|
|
354
|
+
return out
|
|
355
|
+
|
|
356
|
+
def sub(self, repl: str, subject: str) -> str:
|
|
357
|
+
"""Replace every match of the pattern in `subject` with `repl`.
|
|
358
|
+
PCRE2-native backref syntax: $1..$9, ${name}.
|
|
359
|
+
|
|
360
|
+
TODO(v2): support CPython's `count` parameter (limit number of
|
|
361
|
+
replacements). Naive: walk finditer + manual splice; cleaner: loop
|
|
362
|
+
`pcre2_substitute` in non-global mode `count` times.
|
|
363
|
+
|
|
364
|
+
TODO(v2): translate CPython's `\\1`-style backref syntax in `repl`
|
|
365
|
+
to PCRE2's `$1` so users can copy regex code over without
|
|
366
|
+
rewriting replacements. Today `\\1` is treated as a literal."""
|
|
367
|
+
sub_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(subject))
|
|
368
|
+
repl_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(repl))
|
|
369
|
+
# `outlen` is both input (buffer capacity PCRE2 reads on entry) and
|
|
370
|
+
# output (actual bytes written / bytes needed). A plain local +
|
|
371
|
+
# take_ptr avoids needing a separate single-cell storage object.
|
|
372
|
+
# `outbuf` is heap-allocated via UninitHeapStorage -- freed on
|
|
373
|
+
# scope exit, including the raise path and on retry-reassignment.
|
|
374
|
+
# `cap` stays as an explicit UInt64(...) cast because len() returns
|
|
375
|
+
# Int32; the signed->unsigned conversion isn't automatic in TPy
|
|
376
|
+
# (cross-sign widening is unsigned->signed-only). See BUGS.md.
|
|
377
|
+
cap = UInt64(len(subject) * 2 + len(repl) + 16)
|
|
378
|
+
outlen: UInt64 = cap
|
|
379
|
+
outbuf = UninitHeapStorage[UInt8](UInt32.trunc(cap))
|
|
380
|
+
opts = pcre2.PCRE2_SUBSTITUTE_GLOBAL | pcre2.PCRE2_SUBSTITUTE_OVERFLOW_LENGTH
|
|
381
|
+
rc = pcre2.substitute(
|
|
382
|
+
self._code.get(), sub_data, UInt64(len(subject)),
|
|
383
|
+
0, opts, None, self._mctx.get(),
|
|
384
|
+
repl_data, UInt64(len(repl)),
|
|
385
|
+
outbuf.ptr(), take_ptr(outlen),
|
|
386
|
+
)
|
|
387
|
+
if rc == pcre2.PCRE2_ERROR_NOMEMORY:
|
|
388
|
+
# PCRE2 wrote the required size into outlen. Reallocate outbuf
|
|
389
|
+
# at that exact size (reassignment drops the old storage).
|
|
390
|
+
# Drop OVERFLOW_LENGTH on retry: buffer is now correctly sized,
|
|
391
|
+
# and asking for overflow-length again would make PCRE2 redo
|
|
392
|
+
# the sizing pass for nothing.
|
|
393
|
+
outbuf = UninitHeapStorage[UInt8](UInt32.trunc(outlen))
|
|
394
|
+
rc = pcre2.substitute(
|
|
395
|
+
self._code.get(), sub_data, UInt64(len(subject)),
|
|
396
|
+
0, pcre2.PCRE2_SUBSTITUTE_GLOBAL, None,
|
|
397
|
+
self._mctx.get(), repl_data, UInt64(len(repl)),
|
|
398
|
+
outbuf.ptr(), take_ptr(outlen),
|
|
399
|
+
)
|
|
400
|
+
if rc < 0:
|
|
401
|
+
raise error(_pcre2_error_msg(rc))
|
|
402
|
+
return unsafe_str_from_buf(unsafe_cast(outbuf.ptr()), outlen)
|
|
403
|
+
|
|
404
|
+
def split(self, subject: str, maxsplit: Int32 = 0) -> Own[list[str]]:
|
|
405
|
+
"""Split `subject` at each match. `maxsplit=0` means no limit."""
|
|
406
|
+
out: list[str] = []
|
|
407
|
+
offset: UInt64 = 0
|
|
408
|
+
splits: Int32 = 0
|
|
409
|
+
sub_len = UInt64(len(subject))
|
|
410
|
+
s_data: Ptr[readonly[UInt8]] = unsafe_cast(unsafe_ptr(subject))
|
|
411
|
+
md_raw = pcre2.match_data_create_from_pattern(self._code.get(), None)
|
|
412
|
+
if md_raw is None:
|
|
413
|
+
raise error("out of memory allocating match data")
|
|
414
|
+
md = _OwnedMatchData(md_raw)
|
|
415
|
+
while offset <= sub_len:
|
|
416
|
+
if maxsplit > Int32(0) and splits >= maxsplit:
|
|
417
|
+
break
|
|
418
|
+
rc = pcre2.match(self._code.get(), s_data, sub_len, offset,
|
|
419
|
+
0, md.get(), self._mctx.get())
|
|
420
|
+
if rc < 0:
|
|
421
|
+
if rc == pcre2.PCRE2_ERROR_NOMATCH:
|
|
422
|
+
break
|
|
423
|
+
raise error(_pcre2_error_msg(rc)) # md drops
|
|
424
|
+
ovec = pcre2.get_ovector_pointer(md.get())
|
|
425
|
+
mstart = unsafe_load(ovec, 0)
|
|
426
|
+
mend = unsafe_load(ovec, 1)
|
|
427
|
+
out.append(subject[Int32.trunc(offset):Int32.trunc(mstart)])
|
|
428
|
+
if mend == mstart:
|
|
429
|
+
offset = mend + 1
|
|
430
|
+
else:
|
|
431
|
+
offset = mend
|
|
432
|
+
splits += Int32(1)
|
|
433
|
+
out.append(subject[Int32.trunc(offset):])
|
|
434
|
+
return out # md drops at end of scope
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
# ---------- Module-level wrappers ----------
|
|
438
|
+
# CPython's `re.compile` returns a Pattern; we do the same.
|
|
439
|
+
# `re.search("...", subj)` etc. compile-and-throw-away -- the compile cache
|
|
440
|
+
# that CPython has needs module-level mutable state, deferred.
|
|
441
|
+
|
|
442
|
+
def compile(pattern: str, flags: Int32 = NOFLAG) -> Own[Pattern]:
|
|
443
|
+
return Pattern(pattern, flags)
|
|
444
|
+
|
|
445
|
+
def search(pattern: str, subject: str,
|
|
446
|
+
flags: Int32 = NOFLAG) -> Optional[Own[Match]]:
|
|
447
|
+
return Pattern(pattern, flags).search(subject)
|
|
448
|
+
|
|
449
|
+
def match(pattern: str, subject: str,
|
|
450
|
+
flags: Int32 = NOFLAG) -> Optional[Own[Match]]:
|
|
451
|
+
return Pattern(pattern, flags).match(subject)
|
|
452
|
+
|
|
453
|
+
def fullmatch(pattern: str, subject: str,
|
|
454
|
+
flags: Int32 = NOFLAG) -> Optional[Own[Match]]:
|
|
455
|
+
return Pattern(pattern, flags).fullmatch(subject)
|
|
456
|
+
|
|
457
|
+
def findall(pattern: str, subject: str,
|
|
458
|
+
flags: Int32 = NOFLAG) -> Own[list[str]]:
|
|
459
|
+
return Pattern(pattern, flags).findall(subject)
|
|
460
|
+
|
|
461
|
+
def sub(pattern: str, repl: str, subject: str,
|
|
462
|
+
flags: Int32 = NOFLAG) -> str:
|
|
463
|
+
return Pattern(pattern, flags).sub(repl, subject)
|
|
464
|
+
|
|
465
|
+
def split(pattern: str, subject: str, maxsplit: Int32 = Int32(0),
|
|
466
|
+
flags: Int32 = NOFLAG) -> Own[list[str]]:
|
|
467
|
+
return Pattern(pattern, flags).split(subject, maxsplit)
|