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,558 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TurboPython Runtime - Core Utilities
|
|
3
|
+
*
|
|
4
|
+
* Panic handling and pointer operations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#pragma once
|
|
8
|
+
|
|
9
|
+
#include <cmath>
|
|
10
|
+
#include <concepts>
|
|
11
|
+
#include <cstdio>
|
|
12
|
+
#include <cstdlib>
|
|
13
|
+
#include <cxxabi.h>
|
|
14
|
+
#include <exception>
|
|
15
|
+
#include <expected>
|
|
16
|
+
#include <format>
|
|
17
|
+
#include <memory>
|
|
18
|
+
#include <optional>
|
|
19
|
+
#include <ostream>
|
|
20
|
+
#include <string>
|
|
21
|
+
#include <string_view>
|
|
22
|
+
#include <type_traits>
|
|
23
|
+
#include <typeinfo>
|
|
24
|
+
#include <utility>
|
|
25
|
+
#include <variant>
|
|
26
|
+
|
|
27
|
+
#include "throwable.hpp"
|
|
28
|
+
#include "type_traits.hpp"
|
|
29
|
+
|
|
30
|
+
namespace tpy {
|
|
31
|
+
|
|
32
|
+
// Python exception hierarchy. Inherits Throwable -> std::exception so
|
|
33
|
+
// `except as e` borrows route through the Throwable vtable for clone()
|
|
34
|
+
// and __raise__() while plain C++ throw/catch still works.
|
|
35
|
+
struct BaseException : ::tpy::Throwable {
|
|
36
|
+
std::string message;
|
|
37
|
+
BaseException() = default;
|
|
38
|
+
explicit BaseException(std::string msg) : message(std::move(msg)) {}
|
|
39
|
+
explicit BaseException(std::string_view msg) : message(msg) {}
|
|
40
|
+
// Disambiguates string-literal calls that would otherwise be ambiguous
|
|
41
|
+
// between the std::string and std::string_view ctors above.
|
|
42
|
+
explicit BaseException(const char* msg) : message(msg) {}
|
|
43
|
+
const char* what() const noexcept override { return message.c_str(); }
|
|
44
|
+
std::string_view __str__() const { return message; }
|
|
45
|
+
friend std::ostream& operator<<(std::ostream& os, const BaseException& e) { return os << e.message; }
|
|
46
|
+
TPY_THROWABLE_VIRTUALS(BaseException)
|
|
47
|
+
};
|
|
48
|
+
struct Exception : BaseException { using BaseException::BaseException; TPY_THROWABLE_VIRTUALS(Exception) };
|
|
49
|
+
struct ValueError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(ValueError) };
|
|
50
|
+
struct OSError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(OSError) };
|
|
51
|
+
struct FileNotFoundError : OSError { using OSError::OSError; TPY_THROWABLE_VIRTUALS(FileNotFoundError) };
|
|
52
|
+
struct AttributeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(AttributeError) };
|
|
53
|
+
struct AssertionError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(AssertionError) };
|
|
54
|
+
struct IndexError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(IndexError) };
|
|
55
|
+
struct KeyError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(KeyError) };
|
|
56
|
+
struct ArithmeticError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(ArithmeticError) };
|
|
57
|
+
struct ZeroDivisionError : ArithmeticError { using ArithmeticError::ArithmeticError; TPY_THROWABLE_VIRTUALS(ZeroDivisionError) };
|
|
58
|
+
struct OverflowError : ArithmeticError { using ArithmeticError::ArithmeticError; TPY_THROWABLE_VIRTUALS(OverflowError) };
|
|
59
|
+
struct TypeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(TypeError) };
|
|
60
|
+
struct NotImplementedError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(NotImplementedError) };
|
|
61
|
+
struct RuntimeError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(RuntimeError) };
|
|
62
|
+
struct MemoryError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(MemoryError) };
|
|
63
|
+
struct StopIteration : Exception { TPY_THROWABLE_VIRTUALS(StopIteration) };
|
|
64
|
+
struct StopAsyncIteration : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(StopAsyncIteration) };
|
|
65
|
+
struct TimeoutError : Exception { using Exception::Exception; TPY_THROWABLE_VIRTUALS(TimeoutError) };
|
|
66
|
+
|
|
67
|
+
// Forward decl: raise_fixedint_overflow (below) calls tpy_panic, whose
|
|
68
|
+
// definition lives later in this header.
|
|
69
|
+
[[noreturn]] inline void tpy_panic(std::string_view msg);
|
|
70
|
+
|
|
71
|
+
// raise<E>(msg) / raise<E>(fmt, args...) -- throw a Python-shaped exception.
|
|
72
|
+
//
|
|
73
|
+
// Every runtime site that surfaces a catchable error goes through this so
|
|
74
|
+
// the underlying policy (currently always `throw`) can be swapped at compile
|
|
75
|
+
// time later (e.g. abort-on-error builds, or routing to `tpy_panic` in
|
|
76
|
+
// `@noalloc` regions) without rewriting call sites.
|
|
77
|
+
//
|
|
78
|
+
// Two forms:
|
|
79
|
+
// raise<E>(msg) -- pre-built std::string_view message
|
|
80
|
+
// raise<E>(fmt, args...) -- std::format-style; format string validated
|
|
81
|
+
// against the arg types at compile time. Single
|
|
82
|
+
// trailing arg disambiguates against the
|
|
83
|
+
// string_view overload.
|
|
84
|
+
//
|
|
85
|
+
// Not constexpr; calling from a constexpr function is permitted under
|
|
86
|
+
// C++23 P2448 as long as the call is never reached during constant
|
|
87
|
+
// evaluation.
|
|
88
|
+
template<typename E>
|
|
89
|
+
requires std::derived_from<E, BaseException>
|
|
90
|
+
[[noreturn]] inline void raise(std::string_view msg) {
|
|
91
|
+
throw E(msg);
|
|
92
|
+
}
|
|
93
|
+
template<typename E, typename T, typename... Rest>
|
|
94
|
+
requires std::derived_from<E, BaseException>
|
|
95
|
+
[[noreturn]] inline void raise(std::format_string<T, Rest...> fmt, T&& arg,
|
|
96
|
+
Rest&&... rest) {
|
|
97
|
+
throw E(std::format(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// `assert cond[, msg]` failure path. Thin wrapper around `raise<AssertionError>`
|
|
101
|
+
// that supplies the no-message default `"assertion failed"`. Codegen emits
|
|
102
|
+
// `raise_assertion_error()` for `assert cond` (no message) and
|
|
103
|
+
// `raise_assertion_error(<msg-expr>)` for `assert cond, msg`.
|
|
104
|
+
[[noreturn]] inline void raise_assertion_error(std::string_view msg = "assertion failed") {
|
|
105
|
+
raise<AssertionError>(msg);
|
|
106
|
+
}
|
|
107
|
+
template<typename T, typename... Rest>
|
|
108
|
+
[[noreturn]] inline void raise_assertion_error(std::format_string<T, Rest...> fmt, T&& arg,
|
|
109
|
+
Rest&&... rest) {
|
|
110
|
+
raise<AssertionError>(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Per-class raise helpers (Phase 20 Stage 4b). Decouple every runtime
|
|
114
|
+
// throw site from `raise<E>` (which is template-instantiated against the
|
|
115
|
+
// concrete C++ class) so that Stage 4c can move the exception classes
|
|
116
|
+
// out of core.hpp without rewriting every call site. After Stage 4c
|
|
117
|
+
// these helpers move to `lib/tpy/tpy/_builtins/_raise.py` and the
|
|
118
|
+
// forward declarations relocate to throwable.hpp; their bodies become
|
|
119
|
+
// TPy-defined `raise X(msg)` one-liners resolved at link time.
|
|
120
|
+
#define TPY_DEFINE_RAISE_HELPER(name, ExceptionClass) \
|
|
121
|
+
[[noreturn]] inline void name(std::string_view msg) { \
|
|
122
|
+
raise<ExceptionClass>(msg); \
|
|
123
|
+
} \
|
|
124
|
+
template<typename T, typename... Rest> \
|
|
125
|
+
[[noreturn]] inline void name(std::format_string<T, Rest...> fmt, T&& arg, \
|
|
126
|
+
Rest&&... rest) { \
|
|
127
|
+
raise<ExceptionClass>(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...); \
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
TPY_DEFINE_RAISE_HELPER(raise_value_error, ValueError)
|
|
131
|
+
TPY_DEFINE_RAISE_HELPER(raise_type_error, TypeError)
|
|
132
|
+
TPY_DEFINE_RAISE_HELPER(raise_index_error, IndexError)
|
|
133
|
+
TPY_DEFINE_RAISE_HELPER(raise_key_error, KeyError)
|
|
134
|
+
TPY_DEFINE_RAISE_HELPER(raise_attribute_error, AttributeError)
|
|
135
|
+
TPY_DEFINE_RAISE_HELPER(raise_arithmetic_error, ArithmeticError)
|
|
136
|
+
TPY_DEFINE_RAISE_HELPER(raise_zero_division_error, ZeroDivisionError)
|
|
137
|
+
TPY_DEFINE_RAISE_HELPER(raise_overflow_error, OverflowError)
|
|
138
|
+
TPY_DEFINE_RAISE_HELPER(raise_os_error, OSError)
|
|
139
|
+
TPY_DEFINE_RAISE_HELPER(raise_file_not_found_error, FileNotFoundError)
|
|
140
|
+
TPY_DEFINE_RAISE_HELPER(raise_runtime_error, RuntimeError)
|
|
141
|
+
TPY_DEFINE_RAISE_HELPER(raise_not_implemented_error, NotImplementedError)
|
|
142
|
+
TPY_DEFINE_RAISE_HELPER(raise_memory_error, MemoryError)
|
|
143
|
+
|
|
144
|
+
[[noreturn]] inline void raise_stop_iteration() {
|
|
145
|
+
throw StopIteration{};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Fixed-width integer arithmetic overflow. CPython promotes to unbounded
|
|
149
|
+
// BigInt and never overflows; TPy uses fixed-width storage (Int8..Int64,
|
|
150
|
+
// UInt8..UInt64) and panics on overflow by default. Routed through this
|
|
151
|
+
// helper so the policy can be made switchable later (per build / module /
|
|
152
|
+
// function: none / panic / throw OverflowError) without rewriting the call
|
|
153
|
+
// sites. Currently always panics.
|
|
154
|
+
[[noreturn]] inline void raise_fixedint_overflow(std::string_view msg) {
|
|
155
|
+
tpy_panic(msg);
|
|
156
|
+
}
|
|
157
|
+
template<typename T, typename... Rest>
|
|
158
|
+
[[noreturn]] inline void raise_fixedint_overflow(std::format_string<T, Rest...> fmt,
|
|
159
|
+
T&& arg, Rest&&... rest) {
|
|
160
|
+
tpy_panic(std::format(fmt, std::forward<T>(arg), std::forward<Rest>(rest)...));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Portable replacement for std::unexpected(). Some libc++ versions (e.g. zig's
|
|
164
|
+
// bundled clang) expose both the deprecated std::unexpected() function and the
|
|
165
|
+
// C++23 std::unexpected<E> class template, making the name ambiguous. This wrapper
|
|
166
|
+
// avoids naming std::unexpected entirely by using std::unexpect tag construction.
|
|
167
|
+
template<typename E>
|
|
168
|
+
struct Unexpected {
|
|
169
|
+
E error;
|
|
170
|
+
template<typename T>
|
|
171
|
+
operator std::expected<T, E>() && {
|
|
172
|
+
return std::expected<T, E>{std::unexpect, std::move(error)};
|
|
173
|
+
}
|
|
174
|
+
template<typename T>
|
|
175
|
+
operator std::expected<T, E>() const& {
|
|
176
|
+
return std::expected<T, E>{std::unexpect, error};
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
template<typename E>
|
|
181
|
+
Unexpected<std::remove_cvref_t<E>> make_unexpected(E&& e) {
|
|
182
|
+
return Unexpected<std::remove_cvref_t<E>>{std::forward<E>(e)};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// next(iterator) -- forwards __next__() result (std::expected<T, StopIteration>)
|
|
186
|
+
template<typename Iter>
|
|
187
|
+
auto next(Iter& it) -> decltype(it.__next__()) {
|
|
188
|
+
return it.__next__();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Strip the inline-namespace tokens libc++ and libstdc++ inject into
|
|
192
|
+
// demangled std:: type names (`std::__1::basic_string` /
|
|
193
|
+
// `std::__cxx11::basic_string`) and collapse the libstdc++ "> >" template
|
|
194
|
+
// closer to ">>". Without this the panic snapshots would diverge by
|
|
195
|
+
// host standard library.
|
|
196
|
+
inline void normalize_stdlib_typename(std::string& s) {
|
|
197
|
+
auto strip = [&s](std::string_view marker) {
|
|
198
|
+
for (size_t pos = 0; (pos = s.find(marker, pos)) != std::string::npos; ) {
|
|
199
|
+
s.erase(pos, marker.size());
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
strip("__1::");
|
|
203
|
+
strip("__cxx11::");
|
|
204
|
+
for (size_t pos = 0; (pos = s.find("> >", pos)) != std::string::npos; ) {
|
|
205
|
+
s.erase(pos + 1, 1);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Demangle a std::type_info::name() result to a human-readable form
|
|
210
|
+
// (e.g. "tpy::BigInt" instead of "N3tpy6BigIntE"). Used by exception
|
|
211
|
+
// messages that name the offending C++ type. Falls back to the mangled
|
|
212
|
+
// name if demangling fails (typeid name is null-terminated, so the
|
|
213
|
+
// fallback is always usable).
|
|
214
|
+
inline std::string demangle_type_name(const char* mangled) {
|
|
215
|
+
int status = 0;
|
|
216
|
+
char* d = abi::__cxa_demangle(mangled, nullptr, nullptr, &status);
|
|
217
|
+
std::string result = (status == 0 && d) ? std::string(d) : std::string(mangled);
|
|
218
|
+
std::free(d);
|
|
219
|
+
normalize_stdlib_typename(result);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Panic and abort - called on fatal runtime errors.
|
|
225
|
+
*/
|
|
226
|
+
[[noreturn]] inline void tpy_panic(std::string_view msg) {
|
|
227
|
+
std::fputs("TurboPython panic: ", stderr);
|
|
228
|
+
std::fwrite(msg.data(), 1, msg.size(), stderr);
|
|
229
|
+
std::fputc('\n', stderr);
|
|
230
|
+
std::exit(1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Normalizes uncaught-exception output across libstdc++/libc++. Installed from
|
|
234
|
+
// codegen-emitted main() via std::set_terminate; not installed when codegen
|
|
235
|
+
// runs in --no-main mode, so host applications keep their own terminate handler.
|
|
236
|
+
[[noreturn]] inline void tpy_terminate_handler() noexcept {
|
|
237
|
+
std::string type_name = "unknown";
|
|
238
|
+
const char* what_msg = nullptr;
|
|
239
|
+
|
|
240
|
+
// Hold ex across the print: what_msg points into the exception object,
|
|
241
|
+
// which is only guaranteed to outlive any active exception_ptr owning it.
|
|
242
|
+
std::exception_ptr ex = std::current_exception();
|
|
243
|
+
if (ex) {
|
|
244
|
+
try {
|
|
245
|
+
std::rethrow_exception(ex);
|
|
246
|
+
} catch (const std::exception& e) {
|
|
247
|
+
type_name = demangle_type_name(typeid(e).name());
|
|
248
|
+
what_msg = e.what();
|
|
249
|
+
} catch (...) {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Flush any pending pre-panic output (prints from finally bodies,
|
|
254
|
+
// partial lines, etc.) so users see the load-bearing side effects
|
|
255
|
+
// that ran before the panic. `_Exit` below bypasses all stream
|
|
256
|
+
// flushing, so without this the user sees only the panic message.
|
|
257
|
+
// `std::cout` is sync'd with C's stdout by default, so fflush
|
|
258
|
+
// alone covers both streams (avoids dragging in `<iostream>`).
|
|
259
|
+
std::fflush(stdout);
|
|
260
|
+
|
|
261
|
+
std::fputs("TurboPython panic: uncaught ", stderr);
|
|
262
|
+
std::fwrite(type_name.data(), 1, type_name.size(), stderr);
|
|
263
|
+
if (what_msg && *what_msg) {
|
|
264
|
+
std::fputs(": ", stderr);
|
|
265
|
+
std::fputs(what_msg, stderr);
|
|
266
|
+
}
|
|
267
|
+
std::fputc('\n', stderr);
|
|
268
|
+
|
|
269
|
+
std::_Exit(1);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Checked pointer dereference - panics if pointer is null.
|
|
274
|
+
* Used for implicit Ptr[T] -> T coercion.
|
|
275
|
+
*/
|
|
276
|
+
template <typename T>
|
|
277
|
+
T& deref_check(T* ptr) {
|
|
278
|
+
if (ptr == nullptr) {
|
|
279
|
+
tpy_panic("null pointer dereference");
|
|
280
|
+
}
|
|
281
|
+
return *ptr;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
template <typename T>
|
|
285
|
+
const T& deref_check(const T* ptr) {
|
|
286
|
+
if (ptr == nullptr) {
|
|
287
|
+
tpy_panic("null pointer dereference");
|
|
288
|
+
}
|
|
289
|
+
return *ptr;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// User types with __deref__() method
|
|
293
|
+
template <typename T>
|
|
294
|
+
requires requires(T& t) { t.__deref__(); }
|
|
295
|
+
decltype(auto) deref_check(T& obj) {
|
|
296
|
+
return obj.__deref__();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Checked optional dereference - panics if optional is empty.
|
|
301
|
+
*/
|
|
302
|
+
template <typename T>
|
|
303
|
+
T& deref_optional_check(std::optional<T>& opt) {
|
|
304
|
+
if (!opt.has_value()) {
|
|
305
|
+
tpy_panic("null optional dereference");
|
|
306
|
+
}
|
|
307
|
+
return *opt;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
template <typename T>
|
|
311
|
+
const T& deref_optional_check(const std::optional<T>& opt) {
|
|
312
|
+
if (!opt.has_value()) {
|
|
313
|
+
tpy_panic("null optional dereference");
|
|
314
|
+
}
|
|
315
|
+
return *opt;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Checked TypedDict optional-field access -- throws KeyError if the
|
|
320
|
+
* field is absent. Used by codegen for `td["key"]` on a `total=False`
|
|
321
|
+
* TypedDict. Distinct from deref_optional_check (which says "null optional
|
|
322
|
+
* dereference") so it matches the existing TPy KeyError convention for
|
|
323
|
+
* dict[k] misses, and avoids raw std::optional::value() whose
|
|
324
|
+
* bad_optional_access::what() text diverges between libstdc++ and libc++.
|
|
325
|
+
*/
|
|
326
|
+
template <typename T>
|
|
327
|
+
T& typed_dict_field_check(std::optional<T>& opt) {
|
|
328
|
+
if (!opt.has_value()) {
|
|
329
|
+
raise_key_error("KeyError");
|
|
330
|
+
}
|
|
331
|
+
return *opt;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
template <typename T>
|
|
335
|
+
const T& typed_dict_field_check(const std::optional<T>& opt) {
|
|
336
|
+
if (!opt.has_value()) {
|
|
337
|
+
raise_key_error("KeyError");
|
|
338
|
+
}
|
|
339
|
+
return *opt;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Optional truthiness helper - matches Python semantics for Optional[value]:
|
|
344
|
+
* value is truthy only when engaged and contained value is truthy.
|
|
345
|
+
*/
|
|
346
|
+
template <typename T>
|
|
347
|
+
inline bool is_truthy(const std::optional<T>& opt) {
|
|
348
|
+
return opt.has_value() && static_cast<bool>(*opt);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// String truthiness: non-empty is truthy (std::string has no operator bool)
|
|
352
|
+
inline bool is_truthy(const std::optional<std::string>& opt) {
|
|
353
|
+
return opt.has_value() && !opt->empty();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
inline bool is_truthy(const std::optional<std::string_view>& opt) {
|
|
357
|
+
return opt.has_value() && !opt->empty();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Destroy an object at a pointer location.
|
|
362
|
+
* No-op for trivially destructible types (scalars, PODs).
|
|
363
|
+
*/
|
|
364
|
+
template <typename T>
|
|
365
|
+
void destroy_at(T* p) {
|
|
366
|
+
if constexpr (!std::is_trivially_destructible_v<T>) {
|
|
367
|
+
p->~T();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Heap-allocate a T and move-construct it from `value` (combined alloc+init).
|
|
373
|
+
* The std::unique_ptr<T> overload below covers the abstract-@dynamic case
|
|
374
|
+
* where the caller has already heap-allocated; it just releases the handle.
|
|
375
|
+
*/
|
|
376
|
+
template <typename T>
|
|
377
|
+
T* heap_take(T&& value) {
|
|
378
|
+
T* p = static_cast<T*>(::operator new(sizeof(T), std::align_val_t(alignof(T))));
|
|
379
|
+
::new(static_cast<void*>(p)) T(std::move(value));
|
|
380
|
+
return p;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
template <typename T>
|
|
384
|
+
T* heap_take(std::unique_ptr<T> value) {
|
|
385
|
+
return value.release();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Destroy and free a heap-allocated T previously produced by heap_take.
|
|
390
|
+
*
|
|
391
|
+
* For polymorphic T (a class with a virtual destructor -- typically the
|
|
392
|
+
* abstract @dynamic protocol base), uses scalar `delete p`. Per [expr.delete],
|
|
393
|
+
* `delete p` with virtual destructor routes through the vtable's *deleting
|
|
394
|
+
* destructor*, which knows the dynamic type and calls the matching operator
|
|
395
|
+
* delete (aligned form if the dynamic type is over-aligned). This is the
|
|
396
|
+
* correct disposal path -- the compiler handles alignment via the vtable.
|
|
397
|
+
*
|
|
398
|
+
* For non-polymorphic T, manually destroys and frees with the same alignment
|
|
399
|
+
* heap_take used. Static and dynamic types coincide, so alignof(T) matches.
|
|
400
|
+
*/
|
|
401
|
+
template <typename T>
|
|
402
|
+
void heap_release(T* p) {
|
|
403
|
+
if constexpr (std::has_virtual_destructor_v<T>) {
|
|
404
|
+
delete p; // virtual deleting destructor handles alignment + dynamic size
|
|
405
|
+
} else {
|
|
406
|
+
tpy::destroy_at(p);
|
|
407
|
+
::operator delete(p, std::align_val_t(alignof(T)));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Replace the heap-stored T at `p` with `value`, returning the live slot.
|
|
413
|
+
*
|
|
414
|
+
* Concrete T: same allocation, destroy + placement-new. Abstract @dynamic
|
|
415
|
+
* T: the slot's size depends on the dynamic type, so reconstruction
|
|
416
|
+
* requires free + reallocate -- returned pointer differs from input.
|
|
417
|
+
*
|
|
418
|
+
* Precondition: `value` must not alias `*p`. The abstract branch frees
|
|
419
|
+
* `*p` before consuming `value`; an aliased payload would be UAF.
|
|
420
|
+
* Callers must propagate the returned pointer.
|
|
421
|
+
*/
|
|
422
|
+
template <typename T>
|
|
423
|
+
T* heap_replace(T* p, own_param_t<T> value) {
|
|
424
|
+
if constexpr (is_dyn_protocol_base_v<T>) {
|
|
425
|
+
heap_release(p);
|
|
426
|
+
return heap_take(std::move(value));
|
|
427
|
+
} else {
|
|
428
|
+
tpy::destroy_at(p);
|
|
429
|
+
::new(static_cast<void*>(p)) T(std::move(value));
|
|
430
|
+
return p;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Convert a heap-allocated T* into an Own[T] by transferring ownership.
|
|
436
|
+
*
|
|
437
|
+
* Abstract @dynamic T: adopt as unique_ptr<T> (T-typed local impossible).
|
|
438
|
+
* Concrete T: move out, destroy the moved-from slot, free its storage.
|
|
439
|
+
*/
|
|
440
|
+
template <typename T>
|
|
441
|
+
own_return_t<T> transfer_ownership(T* p) {
|
|
442
|
+
if constexpr (is_dyn_protocol_base_v<T>) {
|
|
443
|
+
return std::unique_ptr<T>(p);
|
|
444
|
+
} else {
|
|
445
|
+
T val = std::move(*p);
|
|
446
|
+
tpy::destroy_at(p);
|
|
447
|
+
::operator delete(p, std::align_val_t(alignof(T)));
|
|
448
|
+
return val;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Checked true division for floats -- throws ZeroDivisionError on a
|
|
454
|
+
* zero divisor to match Python semantics.
|
|
455
|
+
*/
|
|
456
|
+
inline constexpr double truediv(double a, double b) {
|
|
457
|
+
if (b == 0.0) raise_zero_division_error("float division by zero");
|
|
458
|
+
return a / b;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Constant-evaluation helpers: std::floor / std::fmod are constexpr under
|
|
462
|
+
// C++23 P1383 in libstdc++ (GCC 13+), but libc++ (Apple clang / macOS) has
|
|
463
|
+
// not shipped that yet. When the stdlib advertises P1383 we call through
|
|
464
|
+
// unconditionally; otherwise we fall back to hand-rolled constexpr paths
|
|
465
|
+
// selected via `if consteval`. Fallbacks are correct for finite values in
|
|
466
|
+
// long long range, which is the regime Final literals live in; the runtime
|
|
467
|
+
// path is unchanged. Once every supported stdlib defines the feature macro,
|
|
468
|
+
// drop the `#else` branches entirely.
|
|
469
|
+
#if defined(__cpp_lib_constexpr_cmath) && __cpp_lib_constexpr_cmath >= 202202L
|
|
470
|
+
#define TPY_CMATH_CONSTEXPR 1
|
|
471
|
+
#else
|
|
472
|
+
#define TPY_CMATH_CONSTEXPR 0
|
|
473
|
+
#endif
|
|
474
|
+
|
|
475
|
+
inline constexpr double floordiv(double a, double b) {
|
|
476
|
+
if (b == 0.0) raise_zero_division_error("float floor division by zero");
|
|
477
|
+
#if TPY_CMATH_CONSTEXPR
|
|
478
|
+
return std::floor(a / b);
|
|
479
|
+
#else
|
|
480
|
+
if consteval {
|
|
481
|
+
double q = a / b;
|
|
482
|
+
long long i = static_cast<long long>(q);
|
|
483
|
+
double d = static_cast<double>(i);
|
|
484
|
+
return (d > q) ? d - 1.0 : d;
|
|
485
|
+
}
|
|
486
|
+
return std::floor(a / b);
|
|
487
|
+
#endif
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
inline constexpr double fmod(double a, double b) {
|
|
491
|
+
if (b == 0.0) raise_zero_division_error("float modulo");
|
|
492
|
+
// Python's `%` uses floor semantics (sign-of-divisor) where C's std::fmod
|
|
493
|
+
// uses truncation (sign-of-dividend). Compute the truncated remainder,
|
|
494
|
+
// shift toward the divisor when the signs disagree, and on zero results
|
|
495
|
+
// adopt the divisor's sign (matches CPython's float_rem in floatobject.c).
|
|
496
|
+
#if TPY_CMATH_CONSTEXPR
|
|
497
|
+
double m = std::fmod(a, b);
|
|
498
|
+
#else
|
|
499
|
+
double m;
|
|
500
|
+
if consteval {
|
|
501
|
+
long long i = static_cast<long long>(a / b);
|
|
502
|
+
m = a - static_cast<double>(i) * b;
|
|
503
|
+
} else {
|
|
504
|
+
m = std::fmod(a, b);
|
|
505
|
+
}
|
|
506
|
+
#endif
|
|
507
|
+
if (m != 0.0) {
|
|
508
|
+
if ((m < 0.0) != (b < 0.0)) m += b;
|
|
509
|
+
} else {
|
|
510
|
+
m = (b < 0.0) ? -0.0 : 0.0;
|
|
511
|
+
}
|
|
512
|
+
return m;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Float32 arithmetic helpers
|
|
516
|
+
inline constexpr float truediv_f32(float a, float b) {
|
|
517
|
+
if (b == 0.0f) raise_zero_division_error("float division by zero");
|
|
518
|
+
return a / b;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
inline constexpr float floordiv_f32(float a, float b) {
|
|
522
|
+
if (b == 0.0f) raise_zero_division_error("float floor division by zero");
|
|
523
|
+
#if TPY_CMATH_CONSTEXPR
|
|
524
|
+
return std::floor(a / b);
|
|
525
|
+
#else
|
|
526
|
+
if consteval {
|
|
527
|
+
float q = a / b;
|
|
528
|
+
long long i = static_cast<long long>(q);
|
|
529
|
+
float d = static_cast<float>(i);
|
|
530
|
+
return (d > q) ? d - 1.0f : d;
|
|
531
|
+
}
|
|
532
|
+
return std::floor(a / b);
|
|
533
|
+
#endif
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
inline constexpr float fmod_f32(float a, float b) {
|
|
537
|
+
if (b == 0.0f) raise_zero_division_error("float modulo");
|
|
538
|
+
// Python's `%` uses floor semantics (sign-of-divisor); see fmod above.
|
|
539
|
+
#if TPY_CMATH_CONSTEXPR
|
|
540
|
+
float m = std::fmod(a, b);
|
|
541
|
+
#else
|
|
542
|
+
float m;
|
|
543
|
+
if consteval {
|
|
544
|
+
long long i = static_cast<long long>(a / b);
|
|
545
|
+
m = a - static_cast<float>(i) * b;
|
|
546
|
+
} else {
|
|
547
|
+
m = std::fmod(a, b);
|
|
548
|
+
}
|
|
549
|
+
#endif
|
|
550
|
+
if (m != 0.0f) {
|
|
551
|
+
if ((m < 0.0f) != (b < 0.0f)) m += b;
|
|
552
|
+
} else {
|
|
553
|
+
m = (b < 0.0f) ? -0.0f : 0.0f;
|
|
554
|
+
}
|
|
555
|
+
return m;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
} // namespace tpy
|