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
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
# random -- CPython-compatible Mersenne Twister (MT19937) + distributions.
|
|
2
|
+
#
|
|
3
|
+
# Pure-TPy port of the upstream MT19937 reference (Matsumoto & Nishimura)
|
|
4
|
+
# and CPython's `_randommodule.c` seeding + CPython's `random.Random`
|
|
5
|
+
# distribution methods. For a non-negative Int32 seed that fits in one
|
|
6
|
+
# uint32 word, getrandbits(32) / random() return byte-identical output to
|
|
7
|
+
# CPython after the same seed. Distributions (gauss, gammavariate,
|
|
8
|
+
# normalvariate, etc.) are straight ports of CPython's Lib/random.py so the
|
|
9
|
+
# per-seed output stream matches CPython exactly -- the cpython-phase test
|
|
10
|
+
# in cases/stdlib/random verifies this.
|
|
11
|
+
#
|
|
12
|
+
# Architecture:
|
|
13
|
+
# - Random: class holding the 624-word MT state vector plus cached
|
|
14
|
+
# second value from gauss() / normalvariate(). Per-instance RNGs and
|
|
15
|
+
# all distribution methods live here.
|
|
16
|
+
# - Module-level `_inst: Random` singleton, mutated in place by `seed()`.
|
|
17
|
+
# Module-level `random()`, `randint()`, ... delegate to `_inst`.
|
|
18
|
+
#
|
|
19
|
+
# Thread safety: the module-level functions share `_inst` and are NOT
|
|
20
|
+
# thread-safe. Concurrent calls from multiple threads can corrupt the
|
|
21
|
+
# 624-word state (double-twist, interleaved index updates, torn reads).
|
|
22
|
+
# This is currently theoretical because TPy has no threading primitives
|
|
23
|
+
# -- when `threading` lands we'll need to pick a model (thread-local
|
|
24
|
+
# _inst / lock inside Random / deprecate module-level in favour of
|
|
25
|
+
# explicit instances) and revisit. CPython punts the same way: its docs
|
|
26
|
+
# tell users to use per-thread `Random()` instances, and free-threaded
|
|
27
|
+
# CPython (PEP 703, 3.13+) added internal locking to the C module.
|
|
28
|
+
# Until then, multi-threaded code should construct its own `Random(seed)`
|
|
29
|
+
# per thread rather than calling `random.random()` directly.
|
|
30
|
+
#
|
|
31
|
+
# TODO -- Tier 2 (should work, haven't pressure-tested):
|
|
32
|
+
# - `getstate()` / `setstate(state)`: TPy can't easily synthesize a
|
|
33
|
+
# 625-tuple to match CPython's state type. A `list[UInt32]`-based
|
|
34
|
+
# shape works but is not CPython-compat.
|
|
35
|
+
#
|
|
36
|
+
# TODO -- Tier 3 (genuinely blocked on language work or missing
|
|
37
|
+
# primitives):
|
|
38
|
+
# - `choices(pop, weights=, cum_weights=, k=)`: mechanical sigs +
|
|
39
|
+
# weighted-selection wiring. The list-literal-vs-Iterable[T]
|
|
40
|
+
# conformance gap that used to block this is now resolved.
|
|
41
|
+
# - `sample(pop, k, counts=None)`: more involved algorithm (reservoir /
|
|
42
|
+
# Floyd's) + same signature shape.
|
|
43
|
+
# - `SystemRandom`: needs class-hierarchy decisions (subclass Random
|
|
44
|
+
# with overrides, or standalone class). The OS entropy primitive
|
|
45
|
+
# itself is wired (see `_os_entropy_uint32`).
|
|
46
|
+
# - `seed(int)` for BigInt / `seed(bytes)` / `seed(str)`: need BigInt
|
|
47
|
+
# word-iteration for the key array and/or bytes hashing.
|
|
48
|
+
# - `binomialvariate(n, p)`: BTRS algorithm (Hormann 1993) is a
|
|
49
|
+
# multi-case state machine and needs gauss()-driven path; defer until
|
|
50
|
+
# demand surfaces.
|
|
51
|
+
#
|
|
52
|
+
# User-visible caveats (limitations of the currently-shipped API):
|
|
53
|
+
# - `seed(n)` takes any Int32 (negatives are mapped to abs()); BigInt /
|
|
54
|
+
# bytes / str seeds are not accepted (see Tier 3 above).
|
|
55
|
+
# - `randint(a, b)` requires `b - a + 1` to fit in Int32. `randint(0,
|
|
56
|
+
# INT32_MAX)` panics on the width computation. Use explicit `Random`
|
|
57
|
+
# instances with custom code for wider ranges today.
|
|
58
|
+
# - `randbytes(n)` produces byte-identical output to CPython's
|
|
59
|
+
# `getrandbits(n*8).to_bytes(n, 'little')` for all n on any host,
|
|
60
|
+
# including `n % 4 != 0` (partial-word packing uses the TOP bytes of
|
|
61
|
+
# the final uint32, per CPython's getrandbits packing).
|
|
62
|
+
# - `getrandbits(0)` raises `ValueError`. CPython returns 0 for k=0;
|
|
63
|
+
# supporting it would require special-casing the BigInt zero return
|
|
64
|
+
# and is rarely used. Match CPython if a real workload needs it.
|
|
65
|
+
# - `choice([])` raises `ValueError`. CPython raises `IndexError`; TPy
|
|
66
|
+
# doesn't yet have `IndexError` as a catchable type (STDLIB_ROADMAP
|
|
67
|
+
# "builtins" section). Switch to `IndexError` once it lands.
|
|
68
|
+
#
|
|
69
|
+
# Uses `UInt32.add_wrap / sub_wrap / mul_wrap / shl_wrap` for the modular
|
|
70
|
+
# arithmetic MT needs (TPy's +/-/*/<< on fixed-width ints are
|
|
71
|
+
# overflow-checked).
|
|
72
|
+
#
|
|
73
|
+
# Performance notes (bench: tpyc -xO, x86_64, ccache):
|
|
74
|
+
# Raw engine (genrand_uint32): ~2 ns/call (hand-C++ same algo: 1.2 ns)
|
|
75
|
+
# random() (genrand_res53): ~7 ns/call (hand-C++ same algo: 3 ns)
|
|
76
|
+
# randint(a, b): ~10 ns/call
|
|
77
|
+
# Comparison: CPython's random() is ~54 ns/call; std::mt19937 (different
|
|
78
|
+
# distribution algo) is ~3 ns/call for `uniform_real_distribution`.
|
|
79
|
+
#
|
|
80
|
+
# The ~0.8-4 ns gap vs same-algorithm hand-C++ is pure TPy safety overhead
|
|
81
|
+
# in the hot path, not codegen style or algorithm. Disassembly of
|
|
82
|
+
# _genrand_uint32 shows four sources, each individually tiny but additive:
|
|
83
|
+
# - `__getitem__` bounds check on `_state[_index]` (`ja` branch +
|
|
84
|
+
# `cmovs` for the negative-index normalize). `_index` is provably in
|
|
85
|
+
# [0, N) from the `if _index >= N: generate()` guard, but the
|
|
86
|
+
# optimizer doesn't see through it.
|
|
87
|
+
# - `add_check<int32_t>` overflow check on `_index += 1` (`jo` branch).
|
|
88
|
+
# `_index` is provably <= N = 624, never overflows.
|
|
89
|
+
# - `-fstack-protector` canary (fs:0x28 load + compare on exit).
|
|
90
|
+
# Build-config overhead, not random-specific.
|
|
91
|
+
#
|
|
92
|
+
# Possible future optimizations when/if the language supports them (none
|
|
93
|
+
# of these are worth adding ad-hoc workarounds for today -- the module is
|
|
94
|
+
# already ~7x faster than CPython, diminishing returns from here):
|
|
95
|
+
# - `@unchecked` / `@noalloc` function attribute that suppresses
|
|
96
|
+
# add_check/sub_check/mul_check and list bounds checks inside the
|
|
97
|
+
# body. Would close most of the gap in one pass.
|
|
98
|
+
# - `tpy.unsafe.get_unchecked(arr, i)` for bounds-free subscript at
|
|
99
|
+
# specific sites. More surgical than @unchecked.
|
|
100
|
+
# - Sema value-range analysis proving `_index in [0, 624)` so the
|
|
101
|
+
# bounds check in `__getitem__` folds away. Already scaffolded for
|
|
102
|
+
# other uses (tpyc/sema/value_range.py); would need plumbing to
|
|
103
|
+
# codegen's __getitem__ lowering.
|
|
104
|
+
# - `-fno-stack-protector` on release / noalloc builds (compiler-flag
|
|
105
|
+
# decision, affects all code).
|
|
106
|
+
# tpy: cpp_namespace("tpystd::random")
|
|
107
|
+
# tpy: include("<tpy/stdlib/random.hpp>")
|
|
108
|
+
from tpy import Int32, UInt8, UInt32, Array, copy
|
|
109
|
+
from tpy.extern import native
|
|
110
|
+
from typing import overload
|
|
111
|
+
import math
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@native("tpy::stdlib::random::os_entropy_uint32")
|
|
115
|
+
def _os_entropy_uint32() -> UInt32: ...
|
|
116
|
+
|
|
117
|
+
_N: Int32 = 624
|
|
118
|
+
_M: Int32 = 397
|
|
119
|
+
_MATRIX_A: UInt32 = 0x9908b0df
|
|
120
|
+
_UPPER_MASK: UInt32 = 0x80000000
|
|
121
|
+
_LOWER_MASK: UInt32 = 0x7fffffff
|
|
122
|
+
|
|
123
|
+
# Constants for distributions, mirroring CPython's Lib/random.py.
|
|
124
|
+
_TWOPI: float = 2.0 * math.pi
|
|
125
|
+
_LOG4: float = math.log(4.0)
|
|
126
|
+
_SG_MAGICCONST: float = 1.0 + math.log(4.5)
|
|
127
|
+
_NV_MAGICCONST: float = 4.0 * math.exp(-0.5) / math.sqrt(2.0)
|
|
128
|
+
|
|
129
|
+
class Random:
|
|
130
|
+
# Inline fixed-size state (std::array<uint32_t, 624>). Stack-allocated,
|
|
131
|
+
# compile-time size enables bounds-check elision in __getitem__, and
|
|
132
|
+
# loop unrolling / auto-vectorization in the twist. Measured ~3x
|
|
133
|
+
# speedup vs list[UInt32] on MT hot path.
|
|
134
|
+
_state: Array[UInt32, 624]
|
|
135
|
+
_index: Int32
|
|
136
|
+
# Cached second value from gauss()'s Box-Muller pair. Matches CPython's
|
|
137
|
+
# self.gauss_next using a bool flag instead of float|None sentinel.
|
|
138
|
+
_gauss_next: float
|
|
139
|
+
_has_gauss_next: bool
|
|
140
|
+
|
|
141
|
+
def __init__(self, seed_value: UInt32 | None = None) -> None:
|
|
142
|
+
# std::array<uint32_t, 624>{} zero-inits every slot.
|
|
143
|
+
self._state = Array[UInt32, 624]()
|
|
144
|
+
self._index = _N
|
|
145
|
+
self._gauss_next = 0.0
|
|
146
|
+
self._has_gauss_next = False
|
|
147
|
+
if seed_value is None:
|
|
148
|
+
self._seed(_os_entropy_uint32())
|
|
149
|
+
else:
|
|
150
|
+
self._seed(seed_value)
|
|
151
|
+
|
|
152
|
+
def _init_genrand(self, s: UInt32) -> None:
|
|
153
|
+
self._state[0] = s
|
|
154
|
+
mti: Int32 = 1
|
|
155
|
+
while mti < _N:
|
|
156
|
+
prev: UInt32 = self._state[mti - 1]
|
|
157
|
+
self._state[mti] = UInt32.add_wrap(
|
|
158
|
+
UInt32.mul_wrap(1812433253, prev ^ (prev >> 30)),
|
|
159
|
+
UInt32(mti),
|
|
160
|
+
)
|
|
161
|
+
mti += 1
|
|
162
|
+
self._index = _N
|
|
163
|
+
|
|
164
|
+
def _seed(self, s: UInt32) -> None:
|
|
165
|
+
# CPython's init_by_array specialised for a single-uint32 key [s].
|
|
166
|
+
self._init_genrand(19650218)
|
|
167
|
+
key0: UInt32 = s
|
|
168
|
+
key_length: Int32 = 1
|
|
169
|
+
i: Int32 = 1
|
|
170
|
+
j: Int32 = 0
|
|
171
|
+
k: Int32 = _N
|
|
172
|
+
if k < key_length:
|
|
173
|
+
k = key_length
|
|
174
|
+
while k > 0:
|
|
175
|
+
prev: UInt32 = self._state[i - 1]
|
|
176
|
+
mixed: UInt32 = UInt32.mul_wrap(prev ^ (prev >> 30), 1664525)
|
|
177
|
+
self._state[i] = UInt32.add_wrap(
|
|
178
|
+
UInt32.add_wrap(self._state[i] ^ mixed, key0),
|
|
179
|
+
UInt32(j),
|
|
180
|
+
)
|
|
181
|
+
i += 1
|
|
182
|
+
j += 1
|
|
183
|
+
if i >= _N:
|
|
184
|
+
self._state[0] = self._state[_N - 1]
|
|
185
|
+
i = 1
|
|
186
|
+
if j >= key_length:
|
|
187
|
+
j = 0
|
|
188
|
+
k -= 1
|
|
189
|
+
k = _N - 1
|
|
190
|
+
while k > 0:
|
|
191
|
+
prev2: UInt32 = self._state[i - 1]
|
|
192
|
+
mixed2: UInt32 = UInt32.mul_wrap(prev2 ^ (prev2 >> 30), 1566083941)
|
|
193
|
+
self._state[i] = UInt32.sub_wrap(self._state[i] ^ mixed2, UInt32(i))
|
|
194
|
+
i += 1
|
|
195
|
+
if i >= _N:
|
|
196
|
+
self._state[0] = self._state[_N - 1]
|
|
197
|
+
i = 1
|
|
198
|
+
k -= 1
|
|
199
|
+
# MSB=1 ensures non-zero initial state.
|
|
200
|
+
self._state[0] = 0x80000000
|
|
201
|
+
self._index = _N
|
|
202
|
+
# Reset cached gauss value on reseed -- matches CPython's
|
|
203
|
+
# Random.seed() setting self.gauss_next = None.
|
|
204
|
+
self._has_gauss_next = False
|
|
205
|
+
|
|
206
|
+
def _generate(self) -> None:
|
|
207
|
+
kk: Int32 = 0
|
|
208
|
+
while kk < _N - _M:
|
|
209
|
+
y: UInt32 = (self._state[kk] & _UPPER_MASK) | (self._state[kk + 1] & _LOWER_MASK)
|
|
210
|
+
mag: UInt32 = 0
|
|
211
|
+
if (y & 1) != 0:
|
|
212
|
+
mag = _MATRIX_A
|
|
213
|
+
self._state[kk] = self._state[kk + _M] ^ (y >> 1) ^ mag
|
|
214
|
+
kk += 1
|
|
215
|
+
while kk < _N - 1:
|
|
216
|
+
y2: UInt32 = (self._state[kk] & _UPPER_MASK) | (self._state[kk + 1] & _LOWER_MASK)
|
|
217
|
+
mag2: UInt32 = 0
|
|
218
|
+
if (y2 & 1) != 0:
|
|
219
|
+
mag2 = _MATRIX_A
|
|
220
|
+
self._state[kk] = self._state[kk + _M - _N] ^ (y2 >> 1) ^ mag2
|
|
221
|
+
kk += 1
|
|
222
|
+
y3: UInt32 = (self._state[_N - 1] & _UPPER_MASK) | (self._state[0] & _LOWER_MASK)
|
|
223
|
+
mag3: UInt32 = 0
|
|
224
|
+
if (y3 & 1) != 0:
|
|
225
|
+
mag3 = _MATRIX_A
|
|
226
|
+
self._state[_N - 1] = self._state[_M - 1] ^ (y3 >> 1) ^ mag3
|
|
227
|
+
self._index = 0
|
|
228
|
+
|
|
229
|
+
def _genrand_uint32(self) -> UInt32:
|
|
230
|
+
if self._index >= _N:
|
|
231
|
+
self._generate()
|
|
232
|
+
y: UInt32 = self._state[self._index]
|
|
233
|
+
self._index += 1
|
|
234
|
+
# Tempering.
|
|
235
|
+
y = y ^ (y >> 11)
|
|
236
|
+
y = y ^ (UInt32.shl_wrap(y, 7) & 0x9d2c5680)
|
|
237
|
+
y = y ^ (UInt32.shl_wrap(y, 15) & 0xefc60000)
|
|
238
|
+
y = y ^ (y >> 18)
|
|
239
|
+
return y
|
|
240
|
+
|
|
241
|
+
def random(self) -> float:
|
|
242
|
+
# genrand_res53 -- 53-bit uniform in [0, 1), matches CPython.
|
|
243
|
+
a: UInt32 = self._genrand_uint32() >> 5 # top 27 bits
|
|
244
|
+
b: UInt32 = self._genrand_uint32() >> 6 # top 26 bits
|
|
245
|
+
return (float(a) * 67108864.0 + float(b)) * (1.0 / 9007199254740992.0)
|
|
246
|
+
|
|
247
|
+
def _genrand_top_bits(self, k: Int32) -> UInt32:
|
|
248
|
+
# k in [1, 32]. Avoids the BigInt promotion that public
|
|
249
|
+
# getrandbits does, so _randbelow's rejection loop stays uint32.
|
|
250
|
+
return self._genrand_uint32() >> UInt32(32 - k)
|
|
251
|
+
|
|
252
|
+
def getrandbits(self, k: Int32) -> int:
|
|
253
|
+
# CPython-compatible: returns an int (BigInt) of k random bits.
|
|
254
|
+
# k in [1, 32] uses one MT word; k > 32 concatenates ceil(k/32)
|
|
255
|
+
# words little-endian (word[0] = low 32 bits), matching CPython.
|
|
256
|
+
if k <= 0:
|
|
257
|
+
raise ValueError("number of bits must be greater than zero")
|
|
258
|
+
if k <= 32:
|
|
259
|
+
return int(self._genrand_top_bits(k))
|
|
260
|
+
numwords: Int32 = (k + 31) // 32
|
|
261
|
+
result: int = int(0)
|
|
262
|
+
i: Int32 = 0
|
|
263
|
+
while i < numwords - 1:
|
|
264
|
+
result = result | (int(self._genrand_uint32()) << (32 * i))
|
|
265
|
+
i += 1
|
|
266
|
+
last_k: Int32 = k - 32 * i
|
|
267
|
+
last_word: UInt32 = self._genrand_uint32() >> UInt32(32 - last_k)
|
|
268
|
+
result = result | (int(last_word) << (32 * i))
|
|
269
|
+
return result
|
|
270
|
+
|
|
271
|
+
# ---------- Integer helpers ----------
|
|
272
|
+
|
|
273
|
+
def _randbelow(self, n: UInt32) -> UInt32:
|
|
274
|
+
# Uniform int in [0, n) via rejection sampling over a top-bits
|
|
275
|
+
# slice where k = bit_length(n). Matches CPython's
|
|
276
|
+
# _randbelow_with_getrandbits. Using bit_length(n-1) would agree
|
|
277
|
+
# for non-power-of-2 widths but draws fewer bits per call for
|
|
278
|
+
# powers of 2, diverging the MT stream from CPython.
|
|
279
|
+
if n == 0:
|
|
280
|
+
raise ValueError("_randbelow requires positive n")
|
|
281
|
+
if n == 1:
|
|
282
|
+
return 0
|
|
283
|
+
m: UInt32 = n
|
|
284
|
+
k: Int32 = 0
|
|
285
|
+
while m > 0:
|
|
286
|
+
k += 1
|
|
287
|
+
m = m >> 1
|
|
288
|
+
r: UInt32 = self._genrand_top_bits(k)
|
|
289
|
+
while r >= n:
|
|
290
|
+
r = self._genrand_top_bits(k)
|
|
291
|
+
return r
|
|
292
|
+
|
|
293
|
+
def randint(self, a: Int32, b: Int32) -> Int32:
|
|
294
|
+
# Inclusive [a, b]. v1 constraint: b - a + 1 must fit in Int32
|
|
295
|
+
# (i.e. b - a <= INT32_MAX - 1). CPython handles arbitrary ints.
|
|
296
|
+
if b < a:
|
|
297
|
+
raise ValueError("empty range for randint()")
|
|
298
|
+
width: Int32 = b - a + 1
|
|
299
|
+
return a + Int32(self._randbelow(UInt32(width)))
|
|
300
|
+
|
|
301
|
+
@overload
|
|
302
|
+
def randrange(self, stop: Int32) -> Int32:
|
|
303
|
+
if stop <= 0:
|
|
304
|
+
raise ValueError("empty range for randrange()")
|
|
305
|
+
return Int32(self._randbelow(UInt32(stop)))
|
|
306
|
+
|
|
307
|
+
@overload
|
|
308
|
+
def randrange(self, start: Int32, stop: Int32) -> Int32:
|
|
309
|
+
if stop <= start:
|
|
310
|
+
raise ValueError("empty range for randrange()")
|
|
311
|
+
return start + Int32(self._randbelow(UInt32(stop - start)))
|
|
312
|
+
|
|
313
|
+
@overload
|
|
314
|
+
def randrange(self, start: Int32, stop: Int32, step: Int32) -> Int32:
|
|
315
|
+
if step == 0:
|
|
316
|
+
raise ValueError("zero step for randrange()")
|
|
317
|
+
width: Int32 = 0
|
|
318
|
+
if step > 0:
|
|
319
|
+
if stop <= start:
|
|
320
|
+
raise ValueError("empty range for randrange()")
|
|
321
|
+
# ceil((stop - start) / step)
|
|
322
|
+
width = (stop - start + step - 1) // step
|
|
323
|
+
else:
|
|
324
|
+
if stop >= start:
|
|
325
|
+
raise ValueError("empty range for randrange()")
|
|
326
|
+
neg_step: Int32 = -step
|
|
327
|
+
width = (start - stop + neg_step - 1) // neg_step
|
|
328
|
+
return start + step * Int32(self._randbelow(UInt32(width)))
|
|
329
|
+
|
|
330
|
+
def randbytes(self, n: Int32) -> bytes:
|
|
331
|
+
# Matches CPython's `self.getrandbits(n * 8).to_bytes(n, 'little')`.
|
|
332
|
+
# Full uint32 chunks yield their 4 bytes low-to-high (little-endian).
|
|
333
|
+
# The last partial word uses its TOP `rem*8` bits (CPython's
|
|
334
|
+
# getrandbits shifts each final word right by `32 - remaining_k`
|
|
335
|
+
# before packing), so the partial bytes come from
|
|
336
|
+
# `(w >> (32 - rem*8 + k*8)) & 0xff` for k in [0, rem).
|
|
337
|
+
if n < 0:
|
|
338
|
+
raise ValueError("n must be non-negative")
|
|
339
|
+
out: bytearray = bytearray()
|
|
340
|
+
i: Int32 = 0
|
|
341
|
+
full: Int32 = n // 4
|
|
342
|
+
while i < full:
|
|
343
|
+
v: UInt32 = self._genrand_uint32()
|
|
344
|
+
out.append(UInt8(v & 0xFF))
|
|
345
|
+
out.append(UInt8((v >> 8) & 0xFF))
|
|
346
|
+
out.append(UInt8((v >> 16) & 0xFF))
|
|
347
|
+
out.append(UInt8((v >> 24) & 0xFF))
|
|
348
|
+
i += 1
|
|
349
|
+
rem: Int32 = n - full * 4
|
|
350
|
+
if rem > 0:
|
|
351
|
+
w: UInt32 = self._genrand_uint32()
|
|
352
|
+
shift_base: Int32 = 32 - rem * 8
|
|
353
|
+
j: Int32 = 0
|
|
354
|
+
while j < rem:
|
|
355
|
+
out.append(UInt8((w >> UInt32(shift_base + j * 8)) & 0xFF))
|
|
356
|
+
j += 1
|
|
357
|
+
return bytes(out)
|
|
358
|
+
|
|
359
|
+
# ---------- Sequence helpers ----------
|
|
360
|
+
|
|
361
|
+
def choice[T](self, seq: list[T]) -> T:
|
|
362
|
+
n: Int32 = Int32(len(seq))
|
|
363
|
+
if n == 0:
|
|
364
|
+
# ValueError instead of CPython's IndexError -- see caveats.
|
|
365
|
+
raise ValueError("Cannot choose from an empty sequence")
|
|
366
|
+
return copy(seq[Int32(self._randbelow(UInt32(n)))])
|
|
367
|
+
|
|
368
|
+
def shuffle[T](self, seq: list[T]) -> None:
|
|
369
|
+
# Fisher-Yates / Durstenfeld in place. Matches CPython's
|
|
370
|
+
# random.shuffle MT call sequence (one _randbelow(i+1) per step,
|
|
371
|
+
# i from len-1 down to 1).
|
|
372
|
+
i: Int32 = Int32(len(seq)) - 1
|
|
373
|
+
while i > 0:
|
|
374
|
+
j: Int32 = Int32(self._randbelow(UInt32(i + 1)))
|
|
375
|
+
tmp: T = copy(seq[i])
|
|
376
|
+
seq[i] = copy(seq[j])
|
|
377
|
+
seq[j] = tmp
|
|
378
|
+
i -= 1
|
|
379
|
+
|
|
380
|
+
# ---------- Continuous distributions ----------
|
|
381
|
+
# All straight ports of CPython's Lib/random.py methods. Byte-identical
|
|
382
|
+
# output on the same seed because libm (cos/sin/log/exp/sqrt) is the
|
|
383
|
+
# same underlying implementation under CPython and TPy on Linux.
|
|
384
|
+
|
|
385
|
+
def uniform(self, a: float, b: float) -> float:
|
|
386
|
+
return a + (b - a) * self.random()
|
|
387
|
+
|
|
388
|
+
def triangular(self, low: float = 0.0, high: float = 1.0, mode: float | None = None) -> float:
|
|
389
|
+
u: float = self.random()
|
|
390
|
+
if high == low:
|
|
391
|
+
return low
|
|
392
|
+
c: float = 0.5
|
|
393
|
+
if mode is not None:
|
|
394
|
+
c = (mode - low) / (high - low)
|
|
395
|
+
if u > c:
|
|
396
|
+
u = 1.0 - u
|
|
397
|
+
c = 1.0 - c
|
|
398
|
+
# CPython swaps low/high here; equivalent rewrite:
|
|
399
|
+
return high + (low - high) * math.sqrt(u * c)
|
|
400
|
+
return low + (high - low) * math.sqrt(u * c)
|
|
401
|
+
|
|
402
|
+
def gauss(self, mu: float, sigma: float) -> float:
|
|
403
|
+
# Box-Muller. Matches CPython's self.gauss(), which caches the
|
|
404
|
+
# second generated value for the next call.
|
|
405
|
+
if self._has_gauss_next:
|
|
406
|
+
z: float = self._gauss_next
|
|
407
|
+
self._has_gauss_next = False
|
|
408
|
+
return mu + z * sigma
|
|
409
|
+
x2pi: float = self.random() * _TWOPI
|
|
410
|
+
g2rad: float = math.sqrt(-2.0 * math.log(1.0 - self.random()))
|
|
411
|
+
z2: float = math.cos(x2pi) * g2rad
|
|
412
|
+
self._gauss_next = math.sin(x2pi) * g2rad
|
|
413
|
+
self._has_gauss_next = True
|
|
414
|
+
return mu + z2 * sigma
|
|
415
|
+
|
|
416
|
+
def normalvariate(self, mu: float, sigma: float) -> float:
|
|
417
|
+
# Kinderman-Monahan method, distinct from gauss(). Matches CPython.
|
|
418
|
+
# Does NOT populate _gauss_next: each call consumes fresh MT words.
|
|
419
|
+
# gauss() and normalvariate() produce uncorrelated streams even when
|
|
420
|
+
# interleaved; _gauss_next is gauss-only state.
|
|
421
|
+
while True:
|
|
422
|
+
u1: float = self.random()
|
|
423
|
+
u2: float = 1.0 - self.random()
|
|
424
|
+
z: float = _NV_MAGICCONST * (u1 - 0.5) / u2
|
|
425
|
+
zz: float = z * z / 4.0
|
|
426
|
+
if zz <= -math.log(u2):
|
|
427
|
+
return mu + z * sigma
|
|
428
|
+
|
|
429
|
+
def lognormvariate(self, mu: float, sigma: float) -> float:
|
|
430
|
+
return math.exp(self.normalvariate(mu, sigma))
|
|
431
|
+
|
|
432
|
+
def expovariate(self, lambd: float) -> float:
|
|
433
|
+
# 1.0 - random() is in (0, 1], so log is in (-inf, 0], result >= 0.
|
|
434
|
+
return -math.log(1.0 - self.random()) / lambd
|
|
435
|
+
|
|
436
|
+
def paretovariate(self, alpha: float) -> float:
|
|
437
|
+
u: float = 1.0 - self.random()
|
|
438
|
+
return u ** (-1.0 / alpha)
|
|
439
|
+
|
|
440
|
+
def weibullvariate(self, alpha: float, beta: float) -> float:
|
|
441
|
+
u: float = 1.0 - self.random()
|
|
442
|
+
return alpha * (-math.log(u)) ** (1.0 / beta)
|
|
443
|
+
|
|
444
|
+
def gammavariate(self, alpha: float, beta: float) -> float:
|
|
445
|
+
# CPython's algorithm: Cheng (1977) for alpha > 1, exponential for
|
|
446
|
+
# alpha == 1, Ahrens-Dieter for 0 < alpha < 1.
|
|
447
|
+
if alpha <= 0.0 or beta <= 0.0:
|
|
448
|
+
raise ValueError("gammavariate: alpha and beta must be > 0")
|
|
449
|
+
if alpha > 1.0:
|
|
450
|
+
ainv: float = math.sqrt(2.0 * alpha - 1.0)
|
|
451
|
+
bbb: float = alpha - _LOG4
|
|
452
|
+
ccc: float = alpha + ainv
|
|
453
|
+
while True:
|
|
454
|
+
u1: float = self.random()
|
|
455
|
+
if u1 <= 1e-7 or u1 >= 0.9999999:
|
|
456
|
+
continue
|
|
457
|
+
u2: float = 1.0 - self.random()
|
|
458
|
+
v: float = math.log(u1 / (1.0 - u1)) / ainv
|
|
459
|
+
x: float = alpha * math.exp(v)
|
|
460
|
+
z: float = u1 * u1 * u2
|
|
461
|
+
r: float = bbb + ccc * v - x
|
|
462
|
+
if r + _SG_MAGICCONST - 4.5 * z >= 0.0 or r >= math.log(z):
|
|
463
|
+
return x * beta
|
|
464
|
+
if alpha == 1.0:
|
|
465
|
+
return -math.log(1.0 - self.random()) * beta
|
|
466
|
+
# 0 < alpha < 1: Ahrens-Dieter rejection sampling.
|
|
467
|
+
b: float = (math.e + alpha) / math.e
|
|
468
|
+
while True:
|
|
469
|
+
u: float = self.random()
|
|
470
|
+
p: float = b * u
|
|
471
|
+
x2: float = 0.0
|
|
472
|
+
if p <= 1.0:
|
|
473
|
+
x2 = p ** (1.0 / alpha)
|
|
474
|
+
else:
|
|
475
|
+
x2 = -math.log((b - p) / alpha)
|
|
476
|
+
u1b: float = self.random()
|
|
477
|
+
if p > 1.0:
|
|
478
|
+
if u1b <= x2 ** (alpha - 1.0):
|
|
479
|
+
return x2 * beta
|
|
480
|
+
else:
|
|
481
|
+
if u1b <= math.exp(-x2):
|
|
482
|
+
return x2 * beta
|
|
483
|
+
|
|
484
|
+
def betavariate(self, alpha: float, beta: float) -> float:
|
|
485
|
+
y: float = self.gammavariate(alpha, 1.0)
|
|
486
|
+
if y <= 0.0:
|
|
487
|
+
return 0.0
|
|
488
|
+
return y / (y + self.gammavariate(beta, 1.0))
|
|
489
|
+
|
|
490
|
+
def vonmisesvariate(self, mu: float, kappa: float) -> float:
|
|
491
|
+
if kappa <= 1e-6:
|
|
492
|
+
return _TWOPI * self.random()
|
|
493
|
+
s: float = 0.5 / kappa
|
|
494
|
+
r: float = s + math.sqrt(1.0 + s * s)
|
|
495
|
+
z: float = 0.0
|
|
496
|
+
while True:
|
|
497
|
+
u1: float = self.random()
|
|
498
|
+
z = math.cos(math.pi * u1)
|
|
499
|
+
d: float = z / (r + z)
|
|
500
|
+
u2: float = self.random()
|
|
501
|
+
if u2 < 1.0 - d * d or u2 <= (1.0 - d) * math.exp(d):
|
|
502
|
+
break
|
|
503
|
+
q: float = 1.0 / r
|
|
504
|
+
f: float = (q + z) / (1.0 + q * z)
|
|
505
|
+
u3: float = self.random()
|
|
506
|
+
mu_mod: float = mu % _TWOPI
|
|
507
|
+
theta: float = 0.0
|
|
508
|
+
if u3 > 0.5:
|
|
509
|
+
theta = mu_mod + math.acos(f)
|
|
510
|
+
else:
|
|
511
|
+
theta = mu_mod - math.acos(f)
|
|
512
|
+
return theta % _TWOPI
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
_inst: Random = Random()
|
|
516
|
+
|
|
517
|
+
# ---------- Module-level convenience API ----------
|
|
518
|
+
# All delegate to the singleton _inst. CPython does the same.
|
|
519
|
+
|
|
520
|
+
def random() -> float:
|
|
521
|
+
return _inst.random()
|
|
522
|
+
|
|
523
|
+
@overload
|
|
524
|
+
def seed() -> None:
|
|
525
|
+
# No-arg form: re-seed from OS entropy (matches CPython's seed()
|
|
526
|
+
# default behavior when called without arguments).
|
|
527
|
+
_inst._seed(_os_entropy_uint32())
|
|
528
|
+
|
|
529
|
+
@overload
|
|
530
|
+
def seed(n: Int32) -> None:
|
|
531
|
+
# CPython treats negative seeds as their absolute value. For
|
|
532
|
+
# INT32_MIN the mathematical abs doesn't fit in Int32, but
|
|
533
|
+
# `0 - n` in UInt32 (mod 2^32) equals abs(n) for any negative n.
|
|
534
|
+
if n < 0:
|
|
535
|
+
_inst._seed(UInt32.sub_wrap(UInt32(0), UInt32.trunc(n)))
|
|
536
|
+
else:
|
|
537
|
+
_inst._seed(UInt32(n))
|
|
538
|
+
|
|
539
|
+
def getrandbits(k: Int32) -> int:
|
|
540
|
+
return _inst.getrandbits(k)
|
|
541
|
+
|
|
542
|
+
def randint(a: Int32, b: Int32) -> Int32:
|
|
543
|
+
return _inst.randint(a, b)
|
|
544
|
+
|
|
545
|
+
def choice[T](seq: list[T]) -> T:
|
|
546
|
+
return _inst.choice(seq)
|
|
547
|
+
|
|
548
|
+
def shuffle[T](seq: list[T]) -> None:
|
|
549
|
+
_inst.shuffle(seq)
|
|
550
|
+
|
|
551
|
+
@overload
|
|
552
|
+
def randrange(stop: Int32) -> Int32:
|
|
553
|
+
return _inst.randrange(stop)
|
|
554
|
+
|
|
555
|
+
@overload
|
|
556
|
+
def randrange(start: Int32, stop: Int32) -> Int32:
|
|
557
|
+
return _inst.randrange(start, stop)
|
|
558
|
+
|
|
559
|
+
@overload
|
|
560
|
+
def randrange(start: Int32, stop: Int32, step: Int32) -> Int32:
|
|
561
|
+
return _inst.randrange(start, stop, step)
|
|
562
|
+
|
|
563
|
+
def randbytes(n: Int32) -> bytes:
|
|
564
|
+
return _inst.randbytes(n)
|
|
565
|
+
|
|
566
|
+
def uniform(a: float, b: float) -> float:
|
|
567
|
+
return _inst.uniform(a, b)
|
|
568
|
+
|
|
569
|
+
def triangular(low: float = 0.0, high: float = 1.0, mode: float | None = None) -> float:
|
|
570
|
+
return _inst.triangular(low, high, mode)
|
|
571
|
+
|
|
572
|
+
def gauss(mu: float, sigma: float) -> float:
|
|
573
|
+
return _inst.gauss(mu, sigma)
|
|
574
|
+
|
|
575
|
+
def normalvariate(mu: float, sigma: float) -> float:
|
|
576
|
+
return _inst.normalvariate(mu, sigma)
|
|
577
|
+
|
|
578
|
+
def lognormvariate(mu: float, sigma: float) -> float:
|
|
579
|
+
return _inst.lognormvariate(mu, sigma)
|
|
580
|
+
|
|
581
|
+
def expovariate(lambd: float) -> float:
|
|
582
|
+
return _inst.expovariate(lambd)
|
|
583
|
+
|
|
584
|
+
def paretovariate(alpha: float) -> float:
|
|
585
|
+
return _inst.paretovariate(alpha)
|
|
586
|
+
|
|
587
|
+
def weibullvariate(alpha: float, beta: float) -> float:
|
|
588
|
+
return _inst.weibullvariate(alpha, beta)
|
|
589
|
+
|
|
590
|
+
def gammavariate(alpha: float, beta: float) -> float:
|
|
591
|
+
return _inst.gammavariate(alpha, beta)
|
|
592
|
+
|
|
593
|
+
def betavariate(alpha: float, beta: float) -> float:
|
|
594
|
+
return _inst.betavariate(alpha, beta)
|
|
595
|
+
|
|
596
|
+
def vonmisesvariate(mu: float, kappa: float) -> float:
|
|
597
|
+
return _inst.vonmisesvariate(mu, kappa)
|