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,354 @@
|
|
|
1
|
+
# tpy: macro_module
|
|
2
|
+
"""Dataclass macro for TurboPython.
|
|
3
|
+
|
|
4
|
+
This module implements @dataclass as a compile-time class macro.
|
|
5
|
+
It is loaded by the compiler via CPython (not compiled to C++).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from tpyc.macro_api import (
|
|
9
|
+
ClassInfo, FieldInfo, TypeInfo, CallMacroContext, MacroArg, MacroError,
|
|
10
|
+
class_macro, call_macro,
|
|
11
|
+
expr_to_cpp_default, ast, types, Expr, Stmt, Function, Type,
|
|
12
|
+
)
|
|
13
|
+
from _macro_helpers import (
|
|
14
|
+
ORDER_DUNDERS, build_init, build_eq, build_repr, build_hash, build_order,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
_MISSING = object()
|
|
18
|
+
|
|
19
|
+
# Module-level registry: tracks which records were built by @dataclass.
|
|
20
|
+
# Class macro writes here; call macros (asdict/astuple) read it.
|
|
21
|
+
_dataclass_records: set[str] = set()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Field:
|
|
25
|
+
"""Descriptor returned by field(). Inspected by @dataclass macro."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, *, default=_MISSING, default_factory=_MISSING):
|
|
28
|
+
if default is not _MISSING and default_factory is not _MISSING:
|
|
29
|
+
raise TypeError("cannot specify both 'default' and 'default_factory'")
|
|
30
|
+
if default is _MISSING and default_factory is _MISSING:
|
|
31
|
+
raise TypeError("requires 'default' or 'default_factory'")
|
|
32
|
+
self.default = default
|
|
33
|
+
self.default_factory = default_factory
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def field(*, default=_MISSING, default_factory=_MISSING) -> Field:
|
|
37
|
+
"""Declare field metadata in @dataclass classes."""
|
|
38
|
+
return Field(default=default, default_factory=default_factory)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@class_macro
|
|
42
|
+
def dataclass(cls: ClassInfo, *, frozen: bool = False, order: bool = False) -> None:
|
|
43
|
+
"""Transform a class into a dataclass with auto-generated methods."""
|
|
44
|
+
cls.is_frozen = frozen
|
|
45
|
+
|
|
46
|
+
_process_field_defaults(cls)
|
|
47
|
+
|
|
48
|
+
# Only inherit fields from parent @dataclass records
|
|
49
|
+
parent_name = cls.parent.name if cls.parent else None
|
|
50
|
+
if parent_name and parent_name in _dataclass_records:
|
|
51
|
+
parent_fields = cls.get_parent_fields()
|
|
52
|
+
_validate_frozen_consistency(cls, frozen)
|
|
53
|
+
else:
|
|
54
|
+
parent_fields = []
|
|
55
|
+
all_fields = parent_fields + cls.fields
|
|
56
|
+
has_parent = len(parent_fields) > 0
|
|
57
|
+
|
|
58
|
+
# Synthesize __init__ (silently skipped when the user wrote one --
|
|
59
|
+
# matches CPython, which also defers to an explicit __init__).
|
|
60
|
+
if not cls.has_method("__init__"):
|
|
61
|
+
if not all_fields:
|
|
62
|
+
raise MacroError(
|
|
63
|
+
f"@dataclass class '{cls.name}' must have at least one field annotation"
|
|
64
|
+
)
|
|
65
|
+
_validate_field_order(cls, all_fields)
|
|
66
|
+
init_fn = build_init(cls, parent_fields, cls.fields)
|
|
67
|
+
cls.add_method(init_fn)
|
|
68
|
+
|
|
69
|
+
# Synthesize __eq__ (silently skipped when the user wrote one).
|
|
70
|
+
if all_fields and not cls.has_method("__eq__"):
|
|
71
|
+
eq_fn = build_eq(cls, all_fields)
|
|
72
|
+
eq_fn.hides_parent = has_parent
|
|
73
|
+
cls.add_method(eq_fn)
|
|
74
|
+
|
|
75
|
+
# Generate __repr__
|
|
76
|
+
if all_fields and not cls.has_method("__repr__"):
|
|
77
|
+
repr_fn = build_repr(cls, all_fields)
|
|
78
|
+
repr_fn.hides_parent = has_parent
|
|
79
|
+
cls.add_method(repr_fn)
|
|
80
|
+
|
|
81
|
+
# Generate __hash__ for frozen dataclasses
|
|
82
|
+
if frozen and all_fields and not cls.has_method("__hash__"):
|
|
83
|
+
hash_fn = build_hash(cls, all_fields)
|
|
84
|
+
hash_fn.hides_parent = has_parent
|
|
85
|
+
cls.add_method(hash_fn)
|
|
86
|
+
|
|
87
|
+
# Generate ordering methods
|
|
88
|
+
if order and all_fields:
|
|
89
|
+
_synthesize_order_methods(cls, all_fields, has_parent)
|
|
90
|
+
|
|
91
|
+
cls.set_match_args([f.name for f in all_fields])
|
|
92
|
+
_dataclass_records.add(cls.name)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _process_field_defaults(cls: ClassInfo) -> None:
|
|
96
|
+
"""Unwrap Field descriptors set by field() calls."""
|
|
97
|
+
for fld in cls.fields:
|
|
98
|
+
if not isinstance(fld.default_obj, Field):
|
|
99
|
+
continue
|
|
100
|
+
spec = fld.default_obj
|
|
101
|
+
if spec.default is not _MISSING:
|
|
102
|
+
fld.set_default(spec.default, default_value=expr_to_cpp_default(spec.default))
|
|
103
|
+
elif spec.default_factory is not _MISSING:
|
|
104
|
+
factory_name = ast.get_name(spec.default_factory)
|
|
105
|
+
if factory_name is None:
|
|
106
|
+
raise MacroError(
|
|
107
|
+
"default_factory must be a type name (e.g., list, dict, MyRecord)",
|
|
108
|
+
loc=fld.loc,
|
|
109
|
+
)
|
|
110
|
+
factory_call = ast.call(factory_name)
|
|
111
|
+
# Preserve source location on the generated call
|
|
112
|
+
factory_call.loc = fld.loc
|
|
113
|
+
fld.set_default(factory_call, is_factory=True)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _validate_frozen_consistency(cls: ClassInfo, frozen: bool) -> None:
|
|
117
|
+
"""Validate frozen/non-frozen consistency across inheritance."""
|
|
118
|
+
result = cls.is_parent_frozen()
|
|
119
|
+
if result is None:
|
|
120
|
+
return
|
|
121
|
+
parent_frozen, parent_name = result
|
|
122
|
+
if parent_frozen and not frozen:
|
|
123
|
+
raise MacroError(
|
|
124
|
+
f"Cannot inherit non-frozen @dataclass '{cls.name}' "
|
|
125
|
+
f"from frozen @dataclass '{parent_name}'"
|
|
126
|
+
)
|
|
127
|
+
if not parent_frozen and frozen:
|
|
128
|
+
raise MacroError(
|
|
129
|
+
f"Cannot inherit frozen @dataclass '{cls.name}' "
|
|
130
|
+
f"from non-frozen @dataclass '{parent_name}'"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _validate_field_order(cls: ClassInfo, all_fields: list[FieldInfo]) -> None:
|
|
135
|
+
"""Validate no non-default field follows a field with default."""
|
|
136
|
+
seen_default = False
|
|
137
|
+
for fld in all_fields:
|
|
138
|
+
if fld.has_default:
|
|
139
|
+
seen_default = True
|
|
140
|
+
elif seen_default:
|
|
141
|
+
raise MacroError(
|
|
142
|
+
f"Field '{fld.name}' without default follows field with default "
|
|
143
|
+
f"in @dataclass class '{cls.name}'",
|
|
144
|
+
loc=fld.loc,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _synthesize_order_methods(
|
|
149
|
+
cls: ClassInfo, all_fields: list[FieldInfo], has_parent: bool,
|
|
150
|
+
) -> None:
|
|
151
|
+
"""Add ordering methods for @dataclass(order=True)."""
|
|
152
|
+
for dunder in ORDER_DUNDERS:
|
|
153
|
+
if cls.has_method(dunder):
|
|
154
|
+
raise MacroError(
|
|
155
|
+
f"@dataclass(order=True) cannot overwrite '{dunder}' "
|
|
156
|
+
f"defined in class '{cls.name}'"
|
|
157
|
+
)
|
|
158
|
+
for fn in build_order(cls, all_fields):
|
|
159
|
+
fn.hides_parent = has_parent
|
|
160
|
+
cls.add_method(fn)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
# Call-site macros: asdict, astuple
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
@call_macro
|
|
168
|
+
def asdict(ctx: CallMacroContext, obj: MacroArg) -> Expr:
|
|
169
|
+
"""Convert a dataclass instance to a dict."""
|
|
170
|
+
return _build_asdict(ctx, obj.expr, obj.type)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _has_dc(ctx: CallMacroContext, type_info: TypeInfo) -> bool:
|
|
174
|
+
"""Check if a type contains dataclass instances needing recursion."""
|
|
175
|
+
inner = type_info.unwrap_optional()
|
|
176
|
+
if inner is not None:
|
|
177
|
+
return _has_dc(ctx, inner)
|
|
178
|
+
if type_info.is_record and type_info.name in _dataclass_records:
|
|
179
|
+
return True
|
|
180
|
+
# Check dict/tuple before iterable -- iterating a dict yields keys,
|
|
181
|
+
# which would incorrectly match dict[DC_Key, V] as list[DC_Key].
|
|
182
|
+
if type_info.is_dict and len(type_info.type_args) == 2:
|
|
183
|
+
return any(_has_dc(ctx, t) for t in type_info.type_args)
|
|
184
|
+
if type_info.is_tuple and type_info.type_args:
|
|
185
|
+
return any(_has_dc(ctx, t) for t in type_info.type_args)
|
|
186
|
+
# Skip sets: the result (dict) isn't hashable, so set[DC] -> set[DC]
|
|
187
|
+
# unchanged (matches CPython). Only recurse into list-like iterables.
|
|
188
|
+
if type_info.is_set:
|
|
189
|
+
return False
|
|
190
|
+
elem = ctx.get_iterable_element_type(type_info)
|
|
191
|
+
if elem is not None and _has_dc(ctx, elem):
|
|
192
|
+
return True
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _value_transform(
|
|
197
|
+
ctx: CallMacroContext, access: Expr, fld_type: TypeInfo,
|
|
198
|
+
dc_fn: 'Callable',
|
|
199
|
+
value_fn: 'Callable',
|
|
200
|
+
) -> Expr:
|
|
201
|
+
"""Shared recursion for _asdict_value / _astuple_value.
|
|
202
|
+
|
|
203
|
+
dc_fn: called for direct dataclass fields (e.g. _build_asdict or _build_astuple)
|
|
204
|
+
value_fn: called recursively for nested elements (e.g. _asdict_value or _astuple_value)
|
|
205
|
+
"""
|
|
206
|
+
# Optional[T] -> None if access is None else recurse(access, T)
|
|
207
|
+
inner = fld_type.unwrap_optional()
|
|
208
|
+
if inner is not None and _has_dc(ctx, inner):
|
|
209
|
+
# Clone to avoid sharing AST nodes between condition and body --
|
|
210
|
+
# sema sets resolved types on nodes, so reuse would cause overwrites.
|
|
211
|
+
transformed = _value_transform(ctx, ast.clone(access), inner, dc_fn, value_fn)
|
|
212
|
+
return ast.if_expr(
|
|
213
|
+
ast.binop(access, "is not", ast.none_lit()),
|
|
214
|
+
transformed,
|
|
215
|
+
ast.none_lit(),
|
|
216
|
+
)
|
|
217
|
+
if fld_type.is_record and fld_type.name in _dataclass_records:
|
|
218
|
+
return dc_fn(ctx, access, fld_type)
|
|
219
|
+
# dict/tuple before iterable (see _has_dc comment)
|
|
220
|
+
if fld_type.is_dict and len(fld_type.type_args) == 2:
|
|
221
|
+
key_type, val_type = fld_type.type_args
|
|
222
|
+
if _has_dc(ctx, key_type) or _has_dc(ctx, val_type):
|
|
223
|
+
return _build_dict_comprehension(ctx, access, key_type, val_type, value_fn)
|
|
224
|
+
if fld_type.is_tuple and fld_type.type_args:
|
|
225
|
+
if any(_has_dc(ctx, t) for t in fld_type.type_args):
|
|
226
|
+
return _build_tuple_expansion(ctx, access, fld_type.type_args, value_fn)
|
|
227
|
+
elem = ctx.get_iterable_element_type(fld_type)
|
|
228
|
+
if elem is not None and _has_dc(ctx, elem):
|
|
229
|
+
var = ast.fresh_tmp("macro")
|
|
230
|
+
return ast.list_comprehension(
|
|
231
|
+
value_fn(ctx, ast.name(var), elem),
|
|
232
|
+
ast.comprehension_generator(var, access),
|
|
233
|
+
)
|
|
234
|
+
return access
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _build_dict_comprehension(
|
|
238
|
+
ctx: CallMacroContext, access: Expr,
|
|
239
|
+
key_type: TypeInfo, val_type: TypeInfo,
|
|
240
|
+
value_fn: 'Callable',
|
|
241
|
+
) -> Expr:
|
|
242
|
+
"""Expand dict field: {f(k): f(v) for k, v in field.items()}"""
|
|
243
|
+
k_var = ast.fresh_tmp("macro")
|
|
244
|
+
v_var = ast.fresh_tmp("macro")
|
|
245
|
+
items_call = ast.method_call(access, "items")
|
|
246
|
+
return ast.dict_comprehension(
|
|
247
|
+
value_fn(ctx, ast.name(k_var), key_type),
|
|
248
|
+
value_fn(ctx, ast.name(v_var), val_type),
|
|
249
|
+
ast.comprehension_generator("__comp_tup", items_call,
|
|
250
|
+
unpack_vars=[k_var, v_var]),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _build_tuple_expansion(
|
|
255
|
+
ctx: CallMacroContext, access: Expr,
|
|
256
|
+
elem_types: list[TypeInfo],
|
|
257
|
+
value_fn: 'Callable',
|
|
258
|
+
) -> Expr:
|
|
259
|
+
"""Expand tuple field: (f(field[0]), f(field[1]), ...)"""
|
|
260
|
+
elements = []
|
|
261
|
+
for i, elem_type in enumerate(elem_types):
|
|
262
|
+
subscript = ast.subscript(access, ast.int_lit(i))
|
|
263
|
+
elements.append(value_fn(ctx, subscript, elem_type))
|
|
264
|
+
return ast.tuple_lit(elements)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _asdict_value(ctx: CallMacroContext, access: Expr, fld_type: TypeInfo) -> Expr:
|
|
268
|
+
"""Build the value expression for a single field in asdict expansion."""
|
|
269
|
+
return _value_transform(ctx, access, fld_type, _build_asdict, _asdict_value)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _build_asdict(ctx: CallMacroContext, expr: Expr, type_info: TypeInfo) -> Expr:
|
|
273
|
+
if type_info.name not in _dataclass_records:
|
|
274
|
+
raise MacroError(f"asdict() requires a @dataclass instance, got '{type_info.name}'")
|
|
275
|
+
fields = ctx.get_record_fields(type_info.name)
|
|
276
|
+
keys = []
|
|
277
|
+
values = []
|
|
278
|
+
value_tpy_types = []
|
|
279
|
+
for fld in fields:
|
|
280
|
+
keys.append(ast.str_lit(fld.name))
|
|
281
|
+
access = ast.field_access(expr, fld.name)
|
|
282
|
+
value = _asdict_value(ctx, access, fld.type)
|
|
283
|
+
values.append(value)
|
|
284
|
+
value_tpy_types.append(_asdict_result_type(ctx, fld.type))
|
|
285
|
+
|
|
286
|
+
dict_literal = ast.dict_lit(keys, values)
|
|
287
|
+
|
|
288
|
+
# For mixed-type fields, wrap in typed dict constructor: dict[str, A|B]({...})
|
|
289
|
+
unique = list(dict.fromkeys(str(t) for t in value_tpy_types))
|
|
290
|
+
if len(unique) > 1:
|
|
291
|
+
value_type = types.union(tuple(value_tpy_types))
|
|
292
|
+
return ast.call("dict", [dict_literal],
|
|
293
|
+
call_type=types.dict(types.str, value_type))
|
|
294
|
+
return dict_literal
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _asdict_result_type(ctx: CallMacroContext, type_info: TypeInfo) -> Type:
|
|
298
|
+
"""Compute the result type for a field in asdict expansion."""
|
|
299
|
+
# Optional[T] -> Optional[result_type(T)]
|
|
300
|
+
inner = type_info.unwrap_optional()
|
|
301
|
+
if inner is not None and _has_dc(ctx, inner):
|
|
302
|
+
return types.optional(_asdict_result_type(ctx, inner))
|
|
303
|
+
# Direct dataclass
|
|
304
|
+
if type_info.is_record and type_info.name in _dataclass_records:
|
|
305
|
+
fields = ctx.get_record_fields(type_info.name)
|
|
306
|
+
if fields is None:
|
|
307
|
+
return type_info.raw_type
|
|
308
|
+
value_types = [_asdict_result_type(ctx, fld.type) for fld in fields]
|
|
309
|
+
unique = list(dict.fromkeys(str(t) for t in value_types))
|
|
310
|
+
if len(unique) > 1:
|
|
311
|
+
return types.dict(types.str, types.union(tuple(value_types)))
|
|
312
|
+
return types.dict(types.str, value_types[0])
|
|
313
|
+
# dict/tuple before iterable (same ordering as _has_dc)
|
|
314
|
+
if type_info.is_dict and len(type_info.type_args) == 2:
|
|
315
|
+
key_type, val_type = type_info.type_args
|
|
316
|
+
if _has_dc(ctx, key_type) or _has_dc(ctx, val_type):
|
|
317
|
+
return types.dict(
|
|
318
|
+
_asdict_result_type(ctx, key_type),
|
|
319
|
+
_asdict_result_type(ctx, val_type),
|
|
320
|
+
)
|
|
321
|
+
if type_info.is_tuple and type_info.type_args:
|
|
322
|
+
if any(_has_dc(ctx, t) for t in type_info.type_args):
|
|
323
|
+
return types.tuple(tuple(
|
|
324
|
+
_asdict_result_type(ctx, t) for t in type_info.type_args
|
|
325
|
+
))
|
|
326
|
+
# list[Dataclass] -> list[dict[...]] (sets excluded by _has_dc)
|
|
327
|
+
elem = ctx.get_iterable_element_type(type_info)
|
|
328
|
+
if elem is not None and _has_dc(ctx, elem):
|
|
329
|
+
return types.list(_asdict_result_type(ctx, elem))
|
|
330
|
+
return type_info.raw_type
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@call_macro
|
|
334
|
+
def astuple(ctx: CallMacroContext, obj: MacroArg) -> Expr:
|
|
335
|
+
"""Convert a dataclass instance to a tuple."""
|
|
336
|
+
return _build_astuple(ctx, obj.expr, obj.type)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _build_astuple(ctx: CallMacroContext, expr: Expr, type_info: TypeInfo) -> Expr:
|
|
340
|
+
# Result type is inferred by sema from the element types;
|
|
341
|
+
# no explicit type annotation needed (unlike _build_asdict for mixed fields).
|
|
342
|
+
if type_info.name not in _dataclass_records:
|
|
343
|
+
raise MacroError(f"astuple() requires a @dataclass instance, got '{type_info.name}'")
|
|
344
|
+
fields = ctx.get_record_fields(type_info.name)
|
|
345
|
+
elements = []
|
|
346
|
+
for fld in fields:
|
|
347
|
+
access = ast.field_access(expr, fld.name)
|
|
348
|
+
elements.append(_astuple_value(ctx, access, fld.type))
|
|
349
|
+
return ast.tuple_lit(elements)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _astuple_value(ctx: CallMacroContext, access: Expr, fld_type: TypeInfo) -> Expr:
|
|
353
|
+
"""Build the value expression for a single field in astuple expansion."""
|
|
354
|
+
return _value_transform(ctx, access, fld_type, _build_astuple, _astuple_value)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# tpy: macro_module
|
|
2
|
+
"""Enum module for TurboPython.
|
|
3
|
+
|
|
4
|
+
Provides Enum, IntEnum base classes and auto() for member values.
|
|
5
|
+
The parser resolves base class names and auto() calls to ("enum", ...)
|
|
6
|
+
via normal import tracking. This module is loaded via CPython during
|
|
7
|
+
compilation (not compiled to C++).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Enum:
|
|
12
|
+
"""Base class for enumeration types."""
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class IntEnum(Enum):
|
|
17
|
+
"""Base class for integer enumeration types."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def auto():
|
|
22
|
+
"""Sentinel for auto-incrementing enum member values."""
|
|
23
|
+
pass
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# functools -- higher-order tools (pure TPy).
|
|
2
|
+
#
|
|
3
|
+
# Surface compared to CPython:
|
|
4
|
+
# - reduce(func, a, initial): 3-arg form on Iterable[T].
|
|
5
|
+
# - reduce(func, a): 2-arg form on list[T] only (random access; raises
|
|
6
|
+
# on empty). TPy lacks CPython's iter/next + StopIteration, so the
|
|
7
|
+
# 2-arg form can't accept arbitrary Iterable[T].
|
|
8
|
+
# - total_ordering: re-exported from `_functools_macros` (sibling
|
|
9
|
+
# macro module).
|
|
10
|
+
#
|
|
11
|
+
# Gaps tracked in STDLIB_ROADMAP.md.
|
|
12
|
+
# tpy: cpp_namespace("tpystd::functools")
|
|
13
|
+
from typing import Iterable, overload
|
|
14
|
+
from tpy import Fn, Own, copy
|
|
15
|
+
from _functools_macros import total_ordering
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@overload
|
|
19
|
+
def reduce[T, U](func: Fn[[U, T], U], a: Iterable[T], initial: U) -> Own[U]:
|
|
20
|
+
acc: U = copy(initial)
|
|
21
|
+
for x in a:
|
|
22
|
+
acc = func(acc, x)
|
|
23
|
+
return acc
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@overload
|
|
27
|
+
def reduce[T](func: Fn[[T, T], T], a: list[T]) -> Own[T]:
|
|
28
|
+
if len(a) == 0:
|
|
29
|
+
raise ValueError("reduce() of empty list with no initial value")
|
|
30
|
+
acc: T = copy(a[0])
|
|
31
|
+
for i in range(1, len(a)):
|
|
32
|
+
acc = func(acc, a[i])
|
|
33
|
+
return acc
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# hashlib -- cryptographic hash algorithms.
|
|
2
|
+
#
|
|
3
|
+
# Only SHA-256 (FIPS 180-4) is shipped today. Pure-TPy straight-line port
|
|
4
|
+
# of the reference algorithm; no SIMD, no OpenSSL binding. Correctness
|
|
5
|
+
# first; an optional fast backend is a future follow-up (see
|
|
6
|
+
# STDLIB_ROADMAP).
|
|
7
|
+
#
|
|
8
|
+
# TODO -- algorithms to add (each follows the same class + factory
|
|
9
|
+
# pattern used by SHA256 below; mechanical copies differing only in
|
|
10
|
+
# round function, initial state, word width, and endianness):
|
|
11
|
+
# - MD5 (RFC 1321) -- UInt32, little-endian state, 128-bit digest
|
|
12
|
+
# - SHA-1 (FIPS 180-4) -- UInt32, big-endian, 160-bit digest
|
|
13
|
+
# - SHA-512 (FIPS 180-4) -- UInt64, big-endian, 512-bit digest
|
|
14
|
+
# - BLAKE2b / BLAKE2s -- separate family, larger surface
|
|
15
|
+
# - SHA-3 / SHAKE -- Keccak sponge, separate algorithm
|
|
16
|
+
#
|
|
17
|
+
# TODO -- module-level surface missing:
|
|
18
|
+
# - `hashlib.new(name, data=None)` -- factory-by-name dispatcher.
|
|
19
|
+
# Needs either a dict-of-factories or runtime type resolution.
|
|
20
|
+
# - `algorithms_available` / `algorithms_guaranteed` -- frozenset[str].
|
|
21
|
+
#
|
|
22
|
+
# TODO -- perf:
|
|
23
|
+
# - Bind OpenSSL / libcrypto as an optional fast backend, gated by the
|
|
24
|
+
# F8 feature-flag system (see FEATURE_ROADMAP.md). Drop-in replacement
|
|
25
|
+
# for the pure-TPy inner loop; pure-TPy stays as deps-free default.
|
|
26
|
+
#
|
|
27
|
+
# Language / compiler gaps hit while porting SHA-256 (see BUGS.md for
|
|
28
|
+
# detail; none of them are hashlib-specific, but they shaped this file):
|
|
29
|
+
# - Default parameter value `b""` rejected as non-constant; we use
|
|
30
|
+
# `bytes | None = None` instead.
|
|
31
|
+
# - Free function with a `bytearray` param + `.append()` inside gets
|
|
32
|
+
# auto-inferred as const, producing "discards qualifiers" C++ errors.
|
|
33
|
+
# Worked around by inlining `_pack_be32` into `digest()`.
|
|
34
|
+
# - Forward-ref string annotations (`-> "SHA256"`) fail parse; class is
|
|
35
|
+
# defined before the factory to avoid them.
|
|
36
|
+
#
|
|
37
|
+
# Uses tpy.bits.rotr32 for rotation and UIntN.add_wrap for wrapping
|
|
38
|
+
# addition (TPy's +/<< on fixed-width ints are overflow-checked; hash
|
|
39
|
+
# algorithms need modular arithmetic).
|
|
40
|
+
# tpy: cpp_namespace("tpystd::hashlib")
|
|
41
|
+
from tpy import Int32, UInt8, UInt32, UInt64, Own
|
|
42
|
+
from tpy.bits import rotr32
|
|
43
|
+
|
|
44
|
+
# ---------- SHA-256 ----------
|
|
45
|
+
|
|
46
|
+
_SHA256_H0: list[UInt32] = [
|
|
47
|
+
UInt32(0x6a09e667), UInt32(0xbb67ae85), UInt32(0x3c6ef372), UInt32(0xa54ff53a),
|
|
48
|
+
UInt32(0x510e527f), UInt32(0x9b05688c), UInt32(0x1f83d9ab), UInt32(0x5be0cd19),
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
_SHA256_K: list[UInt32] = [
|
|
52
|
+
UInt32(0x428a2f98), UInt32(0x71374491), UInt32(0xb5c0fbcf), UInt32(0xe9b5dba5),
|
|
53
|
+
UInt32(0x3956c25b), UInt32(0x59f111f1), UInt32(0x923f82a4), UInt32(0xab1c5ed5),
|
|
54
|
+
UInt32(0xd807aa98), UInt32(0x12835b01), UInt32(0x243185be), UInt32(0x550c7dc3),
|
|
55
|
+
UInt32(0x72be5d74), UInt32(0x80deb1fe), UInt32(0x9bdc06a7), UInt32(0xc19bf174),
|
|
56
|
+
UInt32(0xe49b69c1), UInt32(0xefbe4786), UInt32(0x0fc19dc6), UInt32(0x240ca1cc),
|
|
57
|
+
UInt32(0x2de92c6f), UInt32(0x4a7484aa), UInt32(0x5cb0a9dc), UInt32(0x76f988da),
|
|
58
|
+
UInt32(0x983e5152), UInt32(0xa831c66d), UInt32(0xb00327c8), UInt32(0xbf597fc7),
|
|
59
|
+
UInt32(0xc6e00bf3), UInt32(0xd5a79147), UInt32(0x06ca6351), UInt32(0x14292967),
|
|
60
|
+
UInt32(0x27b70a85), UInt32(0x2e1b2138), UInt32(0x4d2c6dfc), UInt32(0x53380d13),
|
|
61
|
+
UInt32(0x650a7354), UInt32(0x766a0abb), UInt32(0x81c2c92e), UInt32(0x92722c85),
|
|
62
|
+
UInt32(0xa2bfe8a1), UInt32(0xa81a664b), UInt32(0xc24b8b70), UInt32(0xc76c51a3),
|
|
63
|
+
UInt32(0xd192e819), UInt32(0xd6990624), UInt32(0xf40e3585), UInt32(0x106aa070),
|
|
64
|
+
UInt32(0x19a4c116), UInt32(0x1e376c08), UInt32(0x2748774c), UInt32(0x34b0bcb5),
|
|
65
|
+
UInt32(0x391c0cb3), UInt32(0x4ed8aa4a), UInt32(0x5b9cca4f), UInt32(0x682e6ff3),
|
|
66
|
+
UInt32(0x748f82ee), UInt32(0x78a5636f), UInt32(0x84c87814), UInt32(0x8cc70208),
|
|
67
|
+
UInt32(0x90befffa), UInt32(0xa4506ceb), UInt32(0xbef9a3f7), UInt32(0xc67178f2),
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
def _load_be32(data: bytes, off: Int32) -> UInt32:
|
|
71
|
+
return (UInt32(data[off]) << 24) | (UInt32(data[off + 1]) << 16) | (UInt32(data[off + 2]) << 8) | UInt32(data[off + 3])
|
|
72
|
+
|
|
73
|
+
class SHA256:
|
|
74
|
+
h: list[UInt32]
|
|
75
|
+
buffer: bytearray
|
|
76
|
+
length: UInt64
|
|
77
|
+
digest_size: Int32
|
|
78
|
+
block_size: Int32
|
|
79
|
+
name: str
|
|
80
|
+
|
|
81
|
+
def __init__(self) -> None:
|
|
82
|
+
self.h = []
|
|
83
|
+
i: Int32 = 0
|
|
84
|
+
while i < 8:
|
|
85
|
+
self.h.append(_SHA256_H0[i])
|
|
86
|
+
i += 1
|
|
87
|
+
self.buffer = bytearray()
|
|
88
|
+
self.length = 0
|
|
89
|
+
self.digest_size = 32
|
|
90
|
+
self.block_size = 64
|
|
91
|
+
self.name = "sha256"
|
|
92
|
+
|
|
93
|
+
def update(self, data: bytes) -> None:
|
|
94
|
+
n: Int32 = Int32(len(data))
|
|
95
|
+
self.length = UInt64.add_wrap(self.length, UInt64(n))
|
|
96
|
+
k: Int32 = 0
|
|
97
|
+
while k < n:
|
|
98
|
+
self.buffer.append(data[k])
|
|
99
|
+
k += 1
|
|
100
|
+
self._drain_blocks()
|
|
101
|
+
|
|
102
|
+
def _drain_blocks(self) -> None:
|
|
103
|
+
while Int32(len(self.buffer)) >= 64:
|
|
104
|
+
self._process_block(bytes(self.buffer), 0)
|
|
105
|
+
new_buf: bytearray = bytearray()
|
|
106
|
+
j: Int32 = 64
|
|
107
|
+
total: Int32 = Int32(len(self.buffer))
|
|
108
|
+
while j < total:
|
|
109
|
+
new_buf.append(self.buffer[j])
|
|
110
|
+
j += 1
|
|
111
|
+
self.buffer = new_buf
|
|
112
|
+
|
|
113
|
+
def _process_block(self, data: bytes, off: Int32) -> None:
|
|
114
|
+
w: list[UInt32] = []
|
|
115
|
+
i: Int32 = 0
|
|
116
|
+
while i < 16:
|
|
117
|
+
w.append(_load_be32(data, off + 4 * i))
|
|
118
|
+
i += 1
|
|
119
|
+
while i < 64:
|
|
120
|
+
w15: UInt32 = w[i - 15]
|
|
121
|
+
w2: UInt32 = w[i - 2]
|
|
122
|
+
s0: UInt32 = rotr32(w15, 7) ^ rotr32(w15, 18) ^ (w15 >> 3)
|
|
123
|
+
s1: UInt32 = rotr32(w2, 17) ^ rotr32(w2, 19) ^ (w2 >> 10)
|
|
124
|
+
w.append(UInt32.add_wrap(UInt32.add_wrap(UInt32.add_wrap(w[i - 16], s0), w[i - 7]), s1))
|
|
125
|
+
i += 1
|
|
126
|
+
a: UInt32 = self.h[0]
|
|
127
|
+
b: UInt32 = self.h[1]
|
|
128
|
+
c: UInt32 = self.h[2]
|
|
129
|
+
d: UInt32 = self.h[3]
|
|
130
|
+
e: UInt32 = self.h[4]
|
|
131
|
+
f: UInt32 = self.h[5]
|
|
132
|
+
g: UInt32 = self.h[6]
|
|
133
|
+
hh: UInt32 = self.h[7]
|
|
134
|
+
t: Int32 = 0
|
|
135
|
+
while t < 64:
|
|
136
|
+
bsig1: UInt32 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25)
|
|
137
|
+
ch: UInt32 = (e & f) ^ ((~e) & g)
|
|
138
|
+
t1: UInt32 = UInt32.add_wrap(UInt32.add_wrap(UInt32.add_wrap(UInt32.add_wrap(hh, bsig1), ch), _SHA256_K[t]), w[t])
|
|
139
|
+
bsig0: UInt32 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22)
|
|
140
|
+
maj: UInt32 = (a & b) ^ (a & c) ^ (b & c)
|
|
141
|
+
t2: UInt32 = UInt32.add_wrap(bsig0, maj)
|
|
142
|
+
hh = g
|
|
143
|
+
g = f
|
|
144
|
+
f = e
|
|
145
|
+
e = UInt32.add_wrap(d, t1)
|
|
146
|
+
d = c
|
|
147
|
+
c = b
|
|
148
|
+
b = a
|
|
149
|
+
a = UInt32.add_wrap(t1, t2)
|
|
150
|
+
t += 1
|
|
151
|
+
self.h[0] = UInt32.add_wrap(self.h[0], a)
|
|
152
|
+
self.h[1] = UInt32.add_wrap(self.h[1], b)
|
|
153
|
+
self.h[2] = UInt32.add_wrap(self.h[2], c)
|
|
154
|
+
self.h[3] = UInt32.add_wrap(self.h[3], d)
|
|
155
|
+
self.h[4] = UInt32.add_wrap(self.h[4], e)
|
|
156
|
+
self.h[5] = UInt32.add_wrap(self.h[5], f)
|
|
157
|
+
self.h[6] = UInt32.add_wrap(self.h[6], g)
|
|
158
|
+
self.h[7] = UInt32.add_wrap(self.h[7], hh)
|
|
159
|
+
|
|
160
|
+
def digest(self) -> bytes:
|
|
161
|
+
clone: SHA256 = self.copy()
|
|
162
|
+
bit_len: UInt64 = UInt64.add_wrap(clone.length, clone.length)
|
|
163
|
+
bit_len = UInt64.add_wrap(bit_len, bit_len)
|
|
164
|
+
bit_len = UInt64.add_wrap(bit_len, bit_len) # x8 for bits
|
|
165
|
+
clone.buffer.append(0x80)
|
|
166
|
+
while Int32(len(clone.buffer)) % 64 != 56:
|
|
167
|
+
clone.buffer.append(0)
|
|
168
|
+
i: Int32 = 7
|
|
169
|
+
while i >= 0:
|
|
170
|
+
shift: UInt64 = UInt64(i * 8)
|
|
171
|
+
clone.buffer.append(UInt8((bit_len >> shift) & 0xFF))
|
|
172
|
+
i -= 1
|
|
173
|
+
clone._drain_blocks()
|
|
174
|
+
out: bytearray = bytearray()
|
|
175
|
+
i = 0
|
|
176
|
+
while i < 8:
|
|
177
|
+
v: UInt32 = clone.h[i]
|
|
178
|
+
out.append(UInt8((v >> 24) & UInt32(0xFF)))
|
|
179
|
+
out.append(UInt8((v >> 16) & UInt32(0xFF)))
|
|
180
|
+
out.append(UInt8((v >> 8) & UInt32(0xFF)))
|
|
181
|
+
out.append(UInt8(v & UInt32(0xFF)))
|
|
182
|
+
i += 1
|
|
183
|
+
return bytes(out)
|
|
184
|
+
|
|
185
|
+
def hexdigest(self) -> str:
|
|
186
|
+
return self.digest().hex()
|
|
187
|
+
|
|
188
|
+
def copy(self) -> Own[SHA256]:
|
|
189
|
+
c: SHA256 = SHA256()
|
|
190
|
+
i: Int32 = 0
|
|
191
|
+
while i < 8:
|
|
192
|
+
c.h[i] = self.h[i]
|
|
193
|
+
i += 1
|
|
194
|
+
c.length = self.length
|
|
195
|
+
j: Int32 = 0
|
|
196
|
+
n: Int32 = Int32(len(self.buffer))
|
|
197
|
+
while j < n:
|
|
198
|
+
c.buffer.append(self.buffer[j])
|
|
199
|
+
j += 1
|
|
200
|
+
return c
|
|
201
|
+
|
|
202
|
+
def sha256(data: bytes | None = None) -> Own[SHA256]:
|
|
203
|
+
h: SHA256 = SHA256()
|
|
204
|
+
if data is not None:
|
|
205
|
+
h.update(data)
|
|
206
|
+
return h
|