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,954 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TurboPython Runtime - Formatting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Python-style printing for bools, floats, and char-to-string conversion.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#pragma once
|
|
8
|
+
|
|
9
|
+
#include <cassert>
|
|
10
|
+
#include <cctype>
|
|
11
|
+
#include <charconv>
|
|
12
|
+
#include <cmath>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <cstdlib>
|
|
15
|
+
#include <iostream>
|
|
16
|
+
#include <iomanip>
|
|
17
|
+
#include <optional>
|
|
18
|
+
#include <ranges>
|
|
19
|
+
#include <sstream>
|
|
20
|
+
#include <string>
|
|
21
|
+
#include <string_view>
|
|
22
|
+
#include <system_error>
|
|
23
|
+
#include <type_traits>
|
|
24
|
+
#include <vector>
|
|
25
|
+
|
|
26
|
+
#include "core.hpp"
|
|
27
|
+
#include "enum.hpp"
|
|
28
|
+
|
|
29
|
+
namespace tpy {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Helper struct for Python-style bool printing.
|
|
33
|
+
*
|
|
34
|
+
* Matches Python's repr for bools: prints "True" or "False".
|
|
35
|
+
*/
|
|
36
|
+
struct print_bool {
|
|
37
|
+
bool value;
|
|
38
|
+
explicit print_bool(bool v) : value(v) {}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
inline std::ostream& operator<<(std::ostream& os, const print_bool& pb) {
|
|
42
|
+
os << (pb.value ? "True" : "False");
|
|
43
|
+
return os;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Helper struct for float printing that matches Python's repr() behavior.
|
|
48
|
+
*
|
|
49
|
+
* - Whole numbers display with ".0" (e.g., "5.0" not "5")
|
|
50
|
+
* - Large numbers use decimal notation for reasonable range
|
|
51
|
+
* - Very small numbers (< 0.0001) use scientific notation like Python
|
|
52
|
+
* - Uses shortest representation that round-trips correctly
|
|
53
|
+
*/
|
|
54
|
+
struct print_float {
|
|
55
|
+
double value;
|
|
56
|
+
explicit print_float(double v) : value(v) {}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
inline std::string format_float(double value) {
|
|
60
|
+
// Special cases
|
|
61
|
+
if (std::isnan(value)) return "nan";
|
|
62
|
+
if (std::isinf(value)) return value > 0 ? "inf" : "-inf";
|
|
63
|
+
|
|
64
|
+
// Python switches to scientific for |x| < 1e-4 or |x| >= 1e16; otherwise
|
|
65
|
+
// it uses fixed notation. std::to_chars's `shortest` form picks the
|
|
66
|
+
// shortest of the two, which doesn't always agree with Python -- so we
|
|
67
|
+
// pick the format ourselves and hand it to to_chars (no precision arg ->
|
|
68
|
+
// shortest round-tripping form within that format).
|
|
69
|
+
double abs_val = std::fabs(value);
|
|
70
|
+
bool use_scientific = (abs_val != 0.0 && abs_val < 1e-4) || abs_val >= 1e16;
|
|
71
|
+
|
|
72
|
+
// 32 bytes covers the worst case: scientific
|
|
73
|
+
// "-1.7976931348623157e+308" (~24 chars), fixed up to ~22 chars within
|
|
74
|
+
// our [1e-4, 1e16) band. Exponent padding is done on the std::string
|
|
75
|
+
// afterwards, not in this buffer.
|
|
76
|
+
char buf[32];
|
|
77
|
+
auto r = std::to_chars(
|
|
78
|
+
buf, buf + sizeof(buf), value,
|
|
79
|
+
use_scientific ? std::chars_format::scientific : std::chars_format::fixed);
|
|
80
|
+
assert(r.ec == std::errc{});
|
|
81
|
+
std::string s(buf, r.ptr);
|
|
82
|
+
|
|
83
|
+
if (use_scientific) {
|
|
84
|
+
// std::to_chars emits the exponent with no leading zeros (e.g. "1e-5");
|
|
85
|
+
// Python pads single-digit exponents to two digits ("1e-05").
|
|
86
|
+
auto e_pos = s.find('e');
|
|
87
|
+
if (e_pos != std::string::npos) {
|
|
88
|
+
std::size_t digits_pos = e_pos + 2; // skip 'e' and sign
|
|
89
|
+
std::size_t digit_count = s.size() - digits_pos;
|
|
90
|
+
if (digit_count < 2) {
|
|
91
|
+
s.insert(digits_pos, std::string(2 - digit_count, '0'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
// Whole numbers come back without a decimal point (e.g. "1");
|
|
96
|
+
// Python's repr() always shows ".0" for floats.
|
|
97
|
+
if (s.find('.') == std::string::npos) {
|
|
98
|
+
s += ".0";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return s;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
inline std::ostream& operator<<(std::ostream& os, const print_float& pf) {
|
|
105
|
+
os << format_float(pf.value);
|
|
106
|
+
return os;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* repr_quote_string - Python-style repr of a string.
|
|
111
|
+
*
|
|
112
|
+
* Produces the Python repr form: outer quotes plus C-style escapes for
|
|
113
|
+
* `\\`, `\n`, `\r`, `\t`, the active quote character, and other ASCII
|
|
114
|
+
* control bytes (`\xNN`). Bytes >= 0x80 are passed through as-is so a
|
|
115
|
+
* UTF-8-encoded string round-trips visually.
|
|
116
|
+
*
|
|
117
|
+
* Quote selection follows CPython: prefer `'`, switch to `"` only when
|
|
118
|
+
* the string contains `'` and no `"`.
|
|
119
|
+
*/
|
|
120
|
+
inline std::string repr_quote_string(std::string_view s) {
|
|
121
|
+
bool has_single = s.find('\'') != std::string_view::npos;
|
|
122
|
+
bool has_double = s.find('"') != std::string_view::npos;
|
|
123
|
+
char quote = (has_single && !has_double) ? '"' : '\'';
|
|
124
|
+
std::string out;
|
|
125
|
+
out.reserve(s.size() + 2);
|
|
126
|
+
out.push_back(quote);
|
|
127
|
+
for (auto ch : s) {
|
|
128
|
+
unsigned char c = static_cast<unsigned char>(ch);
|
|
129
|
+
switch (c) {
|
|
130
|
+
case '\\': out.append("\\\\"); break;
|
|
131
|
+
case '\n': out.append("\\n"); break;
|
|
132
|
+
case '\r': out.append("\\r"); break;
|
|
133
|
+
case '\t': out.append("\\t"); break;
|
|
134
|
+
default:
|
|
135
|
+
if (ch == quote) {
|
|
136
|
+
out.push_back('\\');
|
|
137
|
+
out.push_back(ch);
|
|
138
|
+
} else if (c < 0x20 || c == 0x7f) {
|
|
139
|
+
static const char kHex[] = "0123456789abcdef";
|
|
140
|
+
out.append("\\x");
|
|
141
|
+
out.push_back(kHex[c >> 4]);
|
|
142
|
+
out.push_back(kHex[c & 0xf]);
|
|
143
|
+
} else {
|
|
144
|
+
out.push_back(ch);
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
out.push_back(quote);
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* char_to_str - Convert a char to a string_view.
|
|
155
|
+
*
|
|
156
|
+
* Returns a string_view pointing to a static single-character string.
|
|
157
|
+
* Uses a lookup table to avoid allocation.
|
|
158
|
+
*/
|
|
159
|
+
inline std::string_view char_to_str(char c) {
|
|
160
|
+
// Static array of single-character null-terminated strings
|
|
161
|
+
static const char chars[256][2] = {
|
|
162
|
+
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
|
|
163
|
+
"\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
|
|
164
|
+
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
|
|
165
|
+
"\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
|
|
166
|
+
" ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
|
|
167
|
+
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
|
|
168
|
+
"@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
|
|
169
|
+
"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
|
|
170
|
+
"`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
|
|
171
|
+
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\x7f",
|
|
172
|
+
"\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87",
|
|
173
|
+
"\x88", "\x89", "\x8a", "\x8b", "\x8c", "\x8d", "\x8e", "\x8f",
|
|
174
|
+
"\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97",
|
|
175
|
+
"\x98", "\x99", "\x9a", "\x9b", "\x9c", "\x9d", "\x9e", "\x9f",
|
|
176
|
+
"\xa0", "\xa1", "\xa2", "\xa3", "\xa4", "\xa5", "\xa6", "\xa7",
|
|
177
|
+
"\xa8", "\xa9", "\xaa", "\xab", "\xac", "\xad", "\xae", "\xaf",
|
|
178
|
+
"\xb0", "\xb1", "\xb2", "\xb3", "\xb4", "\xb5", "\xb6", "\xb7",
|
|
179
|
+
"\xb8", "\xb9", "\xba", "\xbb", "\xbc", "\xbd", "\xbe", "\xbf",
|
|
180
|
+
"\xc0", "\xc1", "\xc2", "\xc3", "\xc4", "\xc5", "\xc6", "\xc7",
|
|
181
|
+
"\xc8", "\xc9", "\xca", "\xcb", "\xcc", "\xcd", "\xce", "\xcf",
|
|
182
|
+
"\xd0", "\xd1", "\xd2", "\xd3", "\xd4", "\xd5", "\xd6", "\xd7",
|
|
183
|
+
"\xd8", "\xd9", "\xda", "\xdb", "\xdc", "\xdd", "\xde", "\xdf",
|
|
184
|
+
"\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7",
|
|
185
|
+
"\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef",
|
|
186
|
+
"\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xf7",
|
|
187
|
+
"\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff"
|
|
188
|
+
};
|
|
189
|
+
return std::string_view(chars[static_cast<unsigned char>(c)], 1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* str_concat - Concatenate two string-like values into a new std::string.
|
|
194
|
+
*
|
|
195
|
+
* Takes both sides as string_view (zero-copy from std::string, string_view,
|
|
196
|
+
* and const char*) and performs a single optimally-sized allocation.
|
|
197
|
+
*/
|
|
198
|
+
inline std::string str_concat(std::string_view a, std::string_view b) {
|
|
199
|
+
std::string result;
|
|
200
|
+
result.reserve(a.size() + b.size());
|
|
201
|
+
result.append(a);
|
|
202
|
+
result.append(b);
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// -- str.split / str.join helpers ------------------------------------------
|
|
207
|
+
// split returns vector<string> (copies) rather than vector<string_view> because
|
|
208
|
+
// TurboPython has no borrow checker to prevent mutation of the source while
|
|
209
|
+
// views exist. A future splitview() could return views for perf-critical code.
|
|
210
|
+
|
|
211
|
+
inline std::vector<std::string> str_split(std::string_view s, std::string_view sep) {
|
|
212
|
+
if (sep.empty()) {
|
|
213
|
+
raise_value_error("empty separator");
|
|
214
|
+
}
|
|
215
|
+
std::vector<std::string> result;
|
|
216
|
+
size_t start = 0;
|
|
217
|
+
while (true) {
|
|
218
|
+
size_t pos = s.find(sep, start);
|
|
219
|
+
if (pos == std::string_view::npos) {
|
|
220
|
+
result.emplace_back(s.substr(start));
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
result.emplace_back(s.substr(start, pos - start));
|
|
224
|
+
start = pos + sep.size();
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
inline std::vector<std::string> str_split(std::string_view s, std::string_view sep, int32_t maxsplit) {
|
|
230
|
+
if (sep.empty()) {
|
|
231
|
+
raise_value_error("empty separator");
|
|
232
|
+
}
|
|
233
|
+
if (maxsplit < 0) {
|
|
234
|
+
return str_split(s, sep);
|
|
235
|
+
}
|
|
236
|
+
std::vector<std::string> result;
|
|
237
|
+
size_t start = 0;
|
|
238
|
+
int32_t splits = 0;
|
|
239
|
+
while (splits < maxsplit) {
|
|
240
|
+
size_t pos = s.find(sep, start);
|
|
241
|
+
if (pos == std::string_view::npos) break;
|
|
242
|
+
result.emplace_back(s.substr(start, pos - start));
|
|
243
|
+
start = pos + sep.size();
|
|
244
|
+
++splits;
|
|
245
|
+
}
|
|
246
|
+
result.emplace_back(s.substr(start));
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
inline std::vector<std::string> str_split_whitespace(std::string_view s) {
|
|
251
|
+
std::vector<std::string> result;
|
|
252
|
+
size_t i = 0;
|
|
253
|
+
while (i < s.size()) {
|
|
254
|
+
while (i < s.size() && std::isspace(static_cast<unsigned char>(s[i]))) ++i;
|
|
255
|
+
if (i >= s.size()) break;
|
|
256
|
+
size_t start = i;
|
|
257
|
+
while (i < s.size() && !std::isspace(static_cast<unsigned char>(s[i]))) ++i;
|
|
258
|
+
result.emplace_back(s.substr(start, i - start));
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
inline std::vector<std::string> str_split_whitespace(std::string_view s, int32_t maxsplit) {
|
|
264
|
+
if (maxsplit < 0) {
|
|
265
|
+
return str_split_whitespace(s);
|
|
266
|
+
}
|
|
267
|
+
std::vector<std::string> result;
|
|
268
|
+
size_t i = 0;
|
|
269
|
+
int32_t splits = 0;
|
|
270
|
+
while (i < s.size()) {
|
|
271
|
+
while (i < s.size() && std::isspace(static_cast<unsigned char>(s[i]))) ++i;
|
|
272
|
+
if (i >= s.size()) break;
|
|
273
|
+
if (splits >= maxsplit) {
|
|
274
|
+
result.emplace_back(s.substr(i));
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
size_t start = i;
|
|
278
|
+
while (i < s.size() && !std::isspace(static_cast<unsigned char>(s[i]))) ++i;
|
|
279
|
+
result.emplace_back(s.substr(start, i - start));
|
|
280
|
+
++splits;
|
|
281
|
+
}
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
template<typename Container>
|
|
286
|
+
requires std::ranges::input_range<const Container>
|
|
287
|
+
inline std::string str_join(std::string_view sep, const Container& items) {
|
|
288
|
+
std::string result;
|
|
289
|
+
bool first = true;
|
|
290
|
+
for (const auto& item : items) {
|
|
291
|
+
if (!first) result.append(sep);
|
|
292
|
+
result.append(std::string_view(item));
|
|
293
|
+
first = false;
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
inline std::string str_join(std::string_view sep, std::initializer_list<const char*> items) {
|
|
299
|
+
std::string result;
|
|
300
|
+
bool first = true;
|
|
301
|
+
for (auto item : items) {
|
|
302
|
+
if (!first) result.append(sep);
|
|
303
|
+
result.append(item);
|
|
304
|
+
first = false;
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
inline std::string str_join(std::string_view sep, std::initializer_list<std::string_view> items) {
|
|
310
|
+
std::string result;
|
|
311
|
+
bool first = true;
|
|
312
|
+
for (auto item : items) {
|
|
313
|
+
if (!first) result.append(sep);
|
|
314
|
+
result.append(item);
|
|
315
|
+
first = false;
|
|
316
|
+
}
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// -- str.strip / lstrip / rstrip -------------------------------------------
|
|
321
|
+
|
|
322
|
+
inline std::string_view str_strip(std::string_view s) {
|
|
323
|
+
size_t start = 0;
|
|
324
|
+
while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
|
|
325
|
+
size_t end = s.size();
|
|
326
|
+
while (end > start && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
|
|
327
|
+
return s.substr(start, end - start);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
inline std::string_view str_lstrip(std::string_view s) {
|
|
331
|
+
size_t start = 0;
|
|
332
|
+
while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
|
|
333
|
+
return s.substr(start);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
inline std::string_view str_rstrip(std::string_view s) {
|
|
337
|
+
size_t end = s.size();
|
|
338
|
+
while (end > 0 && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
|
|
339
|
+
return s.substr(0, end);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// -- str.replace -----------------------------------------------------------
|
|
343
|
+
|
|
344
|
+
inline std::string str_replace(std::string_view s, std::string_view old_sub, std::string_view new_sub) {
|
|
345
|
+
if (old_sub.empty()) {
|
|
346
|
+
// Python semantics: insert new_sub between every character and at both ends
|
|
347
|
+
std::string result;
|
|
348
|
+
result.reserve(s.size() + new_sub.size() * (s.size() + 1));
|
|
349
|
+
for (size_t i = 0; i < s.size(); ++i) {
|
|
350
|
+
result.append(new_sub);
|
|
351
|
+
result += s[i];
|
|
352
|
+
}
|
|
353
|
+
result.append(new_sub);
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
std::string result;
|
|
357
|
+
size_t start = 0;
|
|
358
|
+
while (true) {
|
|
359
|
+
size_t pos = s.find(old_sub, start);
|
|
360
|
+
if (pos == std::string_view::npos) {
|
|
361
|
+
result.append(s.substr(start));
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
result.append(s.substr(start, pos - start));
|
|
365
|
+
result.append(new_sub);
|
|
366
|
+
start = pos + old_sub.size();
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// -- str.find / rfind / index ----------------------------------------------
|
|
372
|
+
|
|
373
|
+
inline int32_t str_find(std::string_view s, std::string_view sub) {
|
|
374
|
+
auto pos = s.find(sub);
|
|
375
|
+
return pos == std::string_view::npos ? -1 : static_cast<int32_t>(pos);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
inline int32_t str_rfind(std::string_view s, std::string_view sub) {
|
|
379
|
+
auto pos = s.rfind(sub);
|
|
380
|
+
return pos == std::string_view::npos ? -1 : static_cast<int32_t>(pos);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
inline int32_t str_index(std::string_view s, std::string_view sub) {
|
|
384
|
+
auto pos = s.find(sub);
|
|
385
|
+
if (pos == std::string_view::npos) {
|
|
386
|
+
raise_value_error("substring not found");
|
|
387
|
+
}
|
|
388
|
+
return static_cast<int32_t>(pos);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// -- str.startswith / endswith ---------------------------------------------
|
|
392
|
+
|
|
393
|
+
inline bool str_startswith(std::string_view s, std::string_view prefix) {
|
|
394
|
+
return s.starts_with(prefix);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
inline bool str_endswith(std::string_view s, std::string_view suffix) {
|
|
398
|
+
return s.ends_with(suffix);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// -- str.upper / lower -----------------------------------------------------
|
|
402
|
+
|
|
403
|
+
inline std::string str_upper(std::string_view s) {
|
|
404
|
+
std::string result(s);
|
|
405
|
+
for (auto& c : result) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
|
|
406
|
+
return result;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
inline std::string str_lower(std::string_view s) {
|
|
410
|
+
std::string result(s);
|
|
411
|
+
for (auto& c : result) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// -- str.__mul__ (string repetition) ---------------------------------------
|
|
416
|
+
|
|
417
|
+
inline std::string str_repeat(std::string_view s, int32_t n) {
|
|
418
|
+
if (n <= 0) return {};
|
|
419
|
+
std::string result;
|
|
420
|
+
result.reserve(s.size() * static_cast<size_t>(n));
|
|
421
|
+
for (int32_t i = 0; i < n; ++i) result.append(s);
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// -- str.count -------------------------------------------------------------
|
|
426
|
+
|
|
427
|
+
inline int32_t str_count(std::string_view s, std::string_view sub) {
|
|
428
|
+
if (sub.empty()) {
|
|
429
|
+
return static_cast<int32_t>(s.size()) + 1;
|
|
430
|
+
}
|
|
431
|
+
int32_t n = 0;
|
|
432
|
+
size_t start = 0;
|
|
433
|
+
while (true) {
|
|
434
|
+
size_t pos = s.find(sub, start);
|
|
435
|
+
if (pos == std::string_view::npos) break;
|
|
436
|
+
++n;
|
|
437
|
+
start = pos + sub.size();
|
|
438
|
+
}
|
|
439
|
+
return n;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// -- str.isdigit / isalpha / isalnum / isspace -----------------------------
|
|
443
|
+
|
|
444
|
+
inline bool str_isdigit(std::string_view s) {
|
|
445
|
+
if (s.empty()) return false;
|
|
446
|
+
for (auto c : s) if (!std::isdigit(static_cast<unsigned char>(c))) return false;
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
inline bool str_isalpha(std::string_view s) {
|
|
451
|
+
if (s.empty()) return false;
|
|
452
|
+
for (auto c : s) if (!std::isalpha(static_cast<unsigned char>(c))) return false;
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
inline bool str_isalnum(std::string_view s) {
|
|
457
|
+
if (s.empty()) return false;
|
|
458
|
+
for (auto c : s) if (!std::isalnum(static_cast<unsigned char>(c))) return false;
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
inline bool str_isspace(std::string_view s) {
|
|
463
|
+
if (s.empty()) return false;
|
|
464
|
+
for (auto c : s) if (!std::isspace(static_cast<unsigned char>(c))) return false;
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// -- str.isupper / islower -------------------------------------------------
|
|
469
|
+
|
|
470
|
+
inline bool str_isupper(std::string_view s) {
|
|
471
|
+
bool has_cased = false;
|
|
472
|
+
for (auto c : s) {
|
|
473
|
+
unsigned char uc = static_cast<unsigned char>(c);
|
|
474
|
+
if (std::islower(uc)) return false;
|
|
475
|
+
if (std::isupper(uc)) has_cased = true;
|
|
476
|
+
}
|
|
477
|
+
return has_cased;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
inline bool str_islower(std::string_view s) {
|
|
481
|
+
bool has_cased = false;
|
|
482
|
+
for (auto c : s) {
|
|
483
|
+
unsigned char uc = static_cast<unsigned char>(c);
|
|
484
|
+
if (std::isupper(uc)) return false;
|
|
485
|
+
if (std::islower(uc)) has_cased = true;
|
|
486
|
+
}
|
|
487
|
+
return has_cased;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// -- str.capitalize / title / swapcase -------------------------------------
|
|
491
|
+
|
|
492
|
+
inline std::string str_capitalize(std::string_view s) {
|
|
493
|
+
std::string result(s);
|
|
494
|
+
if (!result.empty()) {
|
|
495
|
+
result[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(result[0])));
|
|
496
|
+
for (size_t i = 1; i < result.size(); ++i)
|
|
497
|
+
result[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(result[i])));
|
|
498
|
+
}
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
inline std::string str_title(std::string_view s) {
|
|
503
|
+
std::string result(s);
|
|
504
|
+
bool after_boundary = true;
|
|
505
|
+
for (size_t i = 0; i < result.size(); ++i) {
|
|
506
|
+
unsigned char uc = static_cast<unsigned char>(result[i]);
|
|
507
|
+
if (std::isalpha(uc)) {
|
|
508
|
+
result[i] = static_cast<char>(after_boundary ? std::toupper(uc) : std::tolower(uc));
|
|
509
|
+
after_boundary = false;
|
|
510
|
+
} else {
|
|
511
|
+
after_boundary = true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
inline std::string str_swapcase(std::string_view s) {
|
|
518
|
+
std::string result(s);
|
|
519
|
+
for (auto& c : result) {
|
|
520
|
+
unsigned char uc = static_cast<unsigned char>(c);
|
|
521
|
+
if (std::isupper(uc)) c = static_cast<char>(std::tolower(uc));
|
|
522
|
+
else if (std::islower(uc)) c = static_cast<char>(std::toupper(uc));
|
|
523
|
+
}
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// -- str.removeprefix / removesuffix ---------------------------------------
|
|
528
|
+
|
|
529
|
+
inline std::string_view str_removeprefix(std::string_view s, std::string_view prefix) {
|
|
530
|
+
if (s.starts_with(prefix)) return s.substr(prefix.size());
|
|
531
|
+
return s;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
inline std::string_view str_removesuffix(std::string_view s, std::string_view suffix) {
|
|
535
|
+
if (!suffix.empty() && s.ends_with(suffix)) return s.substr(0, s.size() - suffix.size());
|
|
536
|
+
return s;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// -- str.rindex ------------------------------------------------------------
|
|
540
|
+
|
|
541
|
+
inline int32_t str_rindex(std::string_view s, std::string_view sub) {
|
|
542
|
+
auto pos = s.rfind(sub);
|
|
543
|
+
if (pos == std::string_view::npos) {
|
|
544
|
+
raise_value_error("substring not found");
|
|
545
|
+
}
|
|
546
|
+
return static_cast<int32_t>(pos);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// -- str.splitlines --------------------------------------------------------
|
|
550
|
+
|
|
551
|
+
inline std::vector<std::string> str_splitlines(std::string_view s) {
|
|
552
|
+
std::vector<std::string> result;
|
|
553
|
+
size_t start = 0;
|
|
554
|
+
for (size_t i = 0; i < s.size(); ++i) {
|
|
555
|
+
if (s[i] == '\n') {
|
|
556
|
+
result.emplace_back(s.substr(start, i - start));
|
|
557
|
+
start = i + 1;
|
|
558
|
+
} else if (s[i] == '\r') {
|
|
559
|
+
result.emplace_back(s.substr(start, i - start));
|
|
560
|
+
if (i + 1 < s.size() && s[i + 1] == '\n') ++i;
|
|
561
|
+
start = i + 1;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (start < s.size()) {
|
|
565
|
+
result.emplace_back(s.substr(start));
|
|
566
|
+
}
|
|
567
|
+
return result;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* bool_to_str - Convert bool to "True" or "False" string.
|
|
572
|
+
* Returns const char* pointing to static storage (safe for std::string_view).
|
|
573
|
+
*/
|
|
574
|
+
inline const char* bool_to_str(bool x) {
|
|
575
|
+
return x ? "True" : "False";
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* fixed_to_str - Convert any fixed-width integer to string.
|
|
580
|
+
* 8-bit types are promoted to int to avoid char interpretation.
|
|
581
|
+
*/
|
|
582
|
+
template<typename T>
|
|
583
|
+
inline std::string fixed_to_str(T x) {
|
|
584
|
+
if constexpr (sizeof(T) == 1)
|
|
585
|
+
return std::to_string(static_cast<int>(x));
|
|
586
|
+
else
|
|
587
|
+
return std::to_string(x);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* float_to_str - Convert double to string.
|
|
592
|
+
* Produces Python-like output (removes trailing zeros after decimal point).
|
|
593
|
+
* Note: Returns std::string. Caller must ensure the result is used immediately
|
|
594
|
+
* or stored in std::string/auto, not std::string_view.
|
|
595
|
+
*/
|
|
596
|
+
inline std::string float_to_str(double x) {
|
|
597
|
+
// Use Python's repr-like approach: shortest representation that round-trips
|
|
598
|
+
std::ostringstream oss;
|
|
599
|
+
oss << std::setprecision(15) << x;
|
|
600
|
+
std::string result = oss.str();
|
|
601
|
+
|
|
602
|
+
// If no decimal point and no exponent, add .0 for Python compatibility
|
|
603
|
+
if (result.find('.') == std::string::npos && result.find('e') == std::string::npos) {
|
|
604
|
+
result += ".0";
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Remove trailing zeros after decimal point (but keep at least one digit)
|
|
608
|
+
size_t dot = result.find('.');
|
|
609
|
+
if (dot != std::string::npos) {
|
|
610
|
+
size_t e_pos = result.find('e');
|
|
611
|
+
size_t end = (e_pos != std::string::npos) ? e_pos : result.size();
|
|
612
|
+
while (end > dot + 2 && result[end - 1] == '0') {
|
|
613
|
+
--end;
|
|
614
|
+
}
|
|
615
|
+
if (e_pos != std::string::npos) {
|
|
616
|
+
result = result.substr(0, end) + result.substr(e_pos);
|
|
617
|
+
} else {
|
|
618
|
+
result = result.substr(0, end);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* float_from_str - Convert string to double.
|
|
626
|
+
* Panics on invalid input (Python raises ValueError).
|
|
627
|
+
* Supports optional leading/trailing whitespace, sign, and special values
|
|
628
|
+
* "inf", "infinity", "-inf", "-infinity", "nan" (case-insensitive).
|
|
629
|
+
*/
|
|
630
|
+
inline double float_from_str(std::string_view s) {
|
|
631
|
+
size_t start = 0;
|
|
632
|
+
while (start < s.size() && std::isspace(static_cast<unsigned char>(s[start]))) ++start;
|
|
633
|
+
size_t end = s.size();
|
|
634
|
+
while (end > start && std::isspace(static_cast<unsigned char>(s[end - 1]))) --end;
|
|
635
|
+
|
|
636
|
+
if (start >= end) {
|
|
637
|
+
raise_value_error("could not convert string to float: '{}'", s);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
std::string trimmed(s.substr(start, end - start));
|
|
641
|
+
char* endptr;
|
|
642
|
+
double result = std::strtod(trimmed.c_str(), &endptr);
|
|
643
|
+
|
|
644
|
+
if (endptr != trimmed.c_str() + trimmed.size()) {
|
|
645
|
+
raise_value_error("could not convert string to float: '{}'", s);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return result;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* float32_from_str - Convert string to float (32-bit).
|
|
653
|
+
* Same as float_from_str but narrows to single precision.
|
|
654
|
+
* Out-of-range values produce +/-inf (matching Python behavior).
|
|
655
|
+
*/
|
|
656
|
+
inline float float32_from_str(std::string_view s) {
|
|
657
|
+
double d = float_from_str(s);
|
|
658
|
+
return static_cast<float>(d);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* print_optional_val - Print a std::optional<T> as Python would.
|
|
663
|
+
*
|
|
664
|
+
* Prints "None" for empty optional, otherwise prints the value.
|
|
665
|
+
* The Formatter template parameter controls how the value is printed:
|
|
666
|
+
* - void (default): prints the value directly via operator<<
|
|
667
|
+
* - print_bool: prints True/False
|
|
668
|
+
* - print_float: prints Python-style float
|
|
669
|
+
*/
|
|
670
|
+
template<typename Formatter, typename T>
|
|
671
|
+
struct print_optional_val {
|
|
672
|
+
const std::optional<T>& opt;
|
|
673
|
+
explicit print_optional_val(const std::optional<T>& o) : opt(o) {}
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
// Deduction guide: print_optional_val(opt) deduces Formatter=void
|
|
677
|
+
template<typename T>
|
|
678
|
+
print_optional_val(const std::optional<T>&) -> print_optional_val<void, T>;
|
|
679
|
+
|
|
680
|
+
template<typename Formatter, typename T>
|
|
681
|
+
inline std::ostream& operator<<(std::ostream& os, const print_optional_val<Formatter, T>& po) {
|
|
682
|
+
if (po.opt.has_value()) {
|
|
683
|
+
if constexpr (std::is_same_v<Formatter, void>) {
|
|
684
|
+
if constexpr (std::is_enum_v<T>
|
|
685
|
+
&& requires(T x) { ::tpy::EnumUtil<T>::name(x); }) {
|
|
686
|
+
// Enum: route through the shared EnumUtil formatter.
|
|
687
|
+
// Avoids requiring an operator<< for the enum (which
|
|
688
|
+
// @native enums don't emit -- would conflict with any
|
|
689
|
+
// user-provided one).
|
|
690
|
+
::tpy::detail::write_enum_repr(os, *po.opt);
|
|
691
|
+
} else {
|
|
692
|
+
os << *po.opt;
|
|
693
|
+
}
|
|
694
|
+
} else {
|
|
695
|
+
os << Formatter(*po.opt);
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
os << "None";
|
|
699
|
+
}
|
|
700
|
+
return os;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* print_optional - Print a nullable pointer as Python would.
|
|
705
|
+
*
|
|
706
|
+
* Prints "None" for nullptr, otherwise prints the pointed-to value.
|
|
707
|
+
* The optional Formatter template arg (default void) lets callers route
|
|
708
|
+
* the pointee through a wrapper printer -- e.g. ListPrinter<vector<T>>
|
|
709
|
+
* for nullable containers whose underlying type lacks a plain operator<<.
|
|
710
|
+
*/
|
|
711
|
+
template<typename Formatter, typename T>
|
|
712
|
+
struct print_optional {
|
|
713
|
+
const T* ptr;
|
|
714
|
+
explicit print_optional(const T* p) : ptr(p) {}
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
// Deduction guide: print_optional(ptr) deduces Formatter=void.
|
|
718
|
+
template<typename T>
|
|
719
|
+
print_optional(const T*) -> print_optional<void, T>;
|
|
720
|
+
|
|
721
|
+
template<typename Formatter, typename T>
|
|
722
|
+
inline std::ostream& operator<<(std::ostream& os, const print_optional<Formatter, T>& po) {
|
|
723
|
+
if (po.ptr) {
|
|
724
|
+
if constexpr (std::is_same_v<Formatter, void>) {
|
|
725
|
+
os << *(po.ptr);
|
|
726
|
+
} else {
|
|
727
|
+
os << Formatter(*(po.ptr));
|
|
728
|
+
}
|
|
729
|
+
} else {
|
|
730
|
+
os << "None";
|
|
731
|
+
}
|
|
732
|
+
return os;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* ptr_to_optional - Convert a T* nullable pointer to std::optional<T>.
|
|
737
|
+
*
|
|
738
|
+
* nullptr → std::nullopt, otherwise copies the pointed-to value.
|
|
739
|
+
* Used at the T* → std::optional<T> boundary (e.g., assigning a pointer-local
|
|
740
|
+
* to an optional record field).
|
|
741
|
+
*/
|
|
742
|
+
template<typename T>
|
|
743
|
+
std::optional<T> ptr_to_optional(const T* ptr) {
|
|
744
|
+
if (ptr) return *ptr;
|
|
745
|
+
return std::nullopt;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* ptr_to_optional_move - Move a pointee value into a fresh std::optional<T>.
|
|
750
|
+
*
|
|
751
|
+
* nullptr -> std::nullopt; otherwise constructs the optional from std::move
|
|
752
|
+
* of the pointee. Used by Own[tuple[T_ref|None,...]] call sites where sema
|
|
753
|
+
* has cleared each element as movable (last-use lvalue, fresh rvalue, or
|
|
754
|
+
* explicit copy()). Caller is giving up ownership of the pointee; moving
|
|
755
|
+
* lifts to the storage form without copying.
|
|
756
|
+
*/
|
|
757
|
+
template<typename T>
|
|
758
|
+
std::optional<T> ptr_to_optional_move(T* ptr) {
|
|
759
|
+
if (ptr) return std::optional<T>{std::move(*ptr)};
|
|
760
|
+
return std::nullopt;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* optional_to_ptr - Convert std::optional<T>& to T* (mutable).
|
|
765
|
+
*
|
|
766
|
+
* Empty optional → nullptr, otherwise pointer to stored value.
|
|
767
|
+
* Used at the std::optional<T> → T* boundary (e.g., reading an optional
|
|
768
|
+
* record field into a pointer-local variable).
|
|
769
|
+
*/
|
|
770
|
+
template<typename T>
|
|
771
|
+
T* optional_to_ptr(std::optional<T>& opt) {
|
|
772
|
+
if (opt.has_value()) return &*opt;
|
|
773
|
+
return nullptr;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
template<typename T>
|
|
777
|
+
const T* optional_to_ptr(const std::optional<T>& opt) {
|
|
778
|
+
if (opt.has_value()) return &*opt;
|
|
779
|
+
return nullptr;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
namespace detail {
|
|
783
|
+
|
|
784
|
+
// Per-element conversion used by tuple_to_storage / tuple_to_pointer.
|
|
785
|
+
// Dispatch on the destination slot type so mixed tuples (e.g. Ptr[T] +
|
|
786
|
+
// Optional[U]) convert only the slots that need it -- a Src-typed overload
|
|
787
|
+
// set would lift every T*/const T* slot to std::optional regardless of the
|
|
788
|
+
// Dest shape.
|
|
789
|
+
|
|
790
|
+
template<typename Dest, typename Src>
|
|
791
|
+
inline Dest to_optional_form(Src&& s) {
|
|
792
|
+
using SrcD = std::remove_cvref_t<Src>;
|
|
793
|
+
using DestD = std::remove_cvref_t<Dest>;
|
|
794
|
+
if constexpr (std::is_same_v<SrcD, DestD>) {
|
|
795
|
+
return std::forward<Src>(s);
|
|
796
|
+
} else if constexpr (std::is_pointer_v<SrcD>) {
|
|
797
|
+
return ptr_to_optional(s);
|
|
798
|
+
} else {
|
|
799
|
+
return std::forward<Src>(s);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Per-element conversion for tuple_to_storage_move: pointer-form sources
|
|
804
|
+
// move the pointee into the optional; same-shape sources pass through.
|
|
805
|
+
template<typename Dest, typename Src>
|
|
806
|
+
inline Dest to_optional_form_move(Src&& s) {
|
|
807
|
+
using SrcD = std::remove_cvref_t<Src>;
|
|
808
|
+
using DestD = std::remove_cvref_t<Dest>;
|
|
809
|
+
if constexpr (std::is_same_v<SrcD, DestD>) {
|
|
810
|
+
return std::forward<Src>(s);
|
|
811
|
+
} else if constexpr (std::is_pointer_v<SrcD>) {
|
|
812
|
+
return ptr_to_optional_move(s);
|
|
813
|
+
} else {
|
|
814
|
+
return std::forward<Src>(s);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
template<typename Dest, typename Src>
|
|
819
|
+
inline Dest to_pointer_form(Src&& s) {
|
|
820
|
+
using SrcD = std::remove_cvref_t<Src>;
|
|
821
|
+
using DestD = std::remove_cvref_t<Dest>;
|
|
822
|
+
if constexpr (std::is_same_v<SrcD, DestD>) {
|
|
823
|
+
return std::forward<Src>(s);
|
|
824
|
+
} else if constexpr (std::is_pointer_v<SrcD> && std::is_pointer_v<DestD>) {
|
|
825
|
+
// Pointer-form source already; allow implicit qualification adjustment
|
|
826
|
+
// (P* -> const P*) without round-tripping through optional_to_ptr.
|
|
827
|
+
// Removing const would require const_cast and is not a valid use case.
|
|
828
|
+
static_assert(std::is_const_v<std::remove_pointer_t<DestD>>
|
|
829
|
+
|| !std::is_const_v<std::remove_pointer_t<SrcD>>,
|
|
830
|
+
"to_pointer_form: cannot remove const from pointer");
|
|
831
|
+
return s;
|
|
832
|
+
} else if constexpr (std::is_pointer_v<DestD>) {
|
|
833
|
+
return optional_to_ptr(s);
|
|
834
|
+
} else {
|
|
835
|
+
return std::forward<Src>(s);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
} // namespace detail
|
|
840
|
+
|
|
841
|
+
template<typename ToTuple, typename FromTuple, std::size_t... I>
|
|
842
|
+
inline ToTuple tuple_to_storage_impl(FromTuple&& t, std::index_sequence<I...>) {
|
|
843
|
+
return ToTuple(detail::to_optional_form<std::tuple_element_t<I, ToTuple>>(
|
|
844
|
+
std::get<I>(std::forward<FromTuple>(t)))...);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Lift a pointer-form tuple (T*, ..., U) to storage-form (std::optional<T>, ..., U).
|
|
848
|
+
// Plain elements pass through unchanged. Used at field-write boundaries where
|
|
849
|
+
// the field stores std::tuple<std::optional<...>, ...> but the source is a
|
|
850
|
+
// borrow-form tuple from a function return / param / local.
|
|
851
|
+
template<typename ToTuple, typename FromTuple>
|
|
852
|
+
inline ToTuple tuple_to_storage(FromTuple&& t) {
|
|
853
|
+
using F = std::remove_reference_t<FromTuple>;
|
|
854
|
+
return tuple_to_storage_impl<ToTuple>(std::forward<FromTuple>(t),
|
|
855
|
+
std::make_index_sequence<std::tuple_size_v<F>>{});
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
template<typename ToTuple, typename FromTuple, std::size_t... I>
|
|
859
|
+
inline ToTuple tuple_to_storage_move_impl(FromTuple&& t, std::index_sequence<I...>) {
|
|
860
|
+
return ToTuple(detail::to_optional_form_move<std::tuple_element_t<I, ToTuple>>(
|
|
861
|
+
std::get<I>(std::forward<FromTuple>(t)))...);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Move-variant of tuple_to_storage: each pointer-form element's pointee is
|
|
865
|
+
// moved into the destination optional. Emitted at Own[tuple[T_ref|None,...]]
|
|
866
|
+
// call sites where sema has cleared every element as movable (last-use
|
|
867
|
+
// lvalue, fresh rvalue, or explicit copy() rvalue). Required for the
|
|
868
|
+
// move-at-last-use semantic that distinguishes Own[tuple] from a bare-tuple
|
|
869
|
+
// borrow boundary.
|
|
870
|
+
template<typename ToTuple, typename FromTuple>
|
|
871
|
+
inline ToTuple tuple_to_storage_move(FromTuple&& t) {
|
|
872
|
+
using F = std::remove_reference_t<FromTuple>;
|
|
873
|
+
return tuple_to_storage_move_impl<ToTuple>(std::forward<FromTuple>(t),
|
|
874
|
+
std::make_index_sequence<std::tuple_size_v<F>>{});
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
template<typename ToTuple, typename FromTuple, std::size_t... I>
|
|
878
|
+
inline ToTuple tuple_to_pointer_impl(FromTuple&& t, std::index_sequence<I...>) {
|
|
879
|
+
return ToTuple(detail::to_pointer_form<std::tuple_element_t<I, ToTuple>>(
|
|
880
|
+
std::get<I>(std::forward<FromTuple>(t)))...);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// Lower a storage-form tuple (std::optional<T>, ..., U) to pointer-form
|
|
884
|
+
// (T*, ..., U). Plain elements pass through unchanged. Used at field-read
|
|
885
|
+
// boundaries where the consumer is a pointer-form tuple param.
|
|
886
|
+
template<typename ToTuple, typename FromTuple>
|
|
887
|
+
inline ToTuple tuple_to_pointer(FromTuple&& t) {
|
|
888
|
+
using F = std::remove_reference_t<FromTuple>;
|
|
889
|
+
return tuple_to_pointer_impl<ToTuple>(std::forward<FromTuple>(t),
|
|
890
|
+
std::make_index_sequence<std::tuple_size_v<F>>{});
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
namespace detail {
|
|
894
|
+
|
|
895
|
+
// Per-element conversion from a value-form source slot to the corresponding
|
|
896
|
+
// borrow-form destination slot. `s` is always an lvalue ref to a slot in
|
|
897
|
+
// the source value tuple, so taking addresses / binding refs is safe -- the
|
|
898
|
+
// caller's tuple temp lives for the whole full-expression.
|
|
899
|
+
//
|
|
900
|
+
// Source slots may already be in borrow form when codegen mixes rvalue and
|
|
901
|
+
// lvalue elements at the same site (e.g. (T(1), &local) -> std::tuple<T,
|
|
902
|
+
// T*>): same-shape Src/Dest pass through; only Src=value + Dest=pointer
|
|
903
|
+
// takes the address.
|
|
904
|
+
template<typename Dest, typename Src>
|
|
905
|
+
inline Dest borrow_value_elem(Src& s) {
|
|
906
|
+
using DestNoRef = std::remove_reference_t<Dest>;
|
|
907
|
+
using SrcD = std::remove_cv_t<Src>;
|
|
908
|
+
using DestNoRefCV = std::remove_cv_t<DestNoRef>;
|
|
909
|
+
if constexpr (std::is_same_v<SrcD, DestNoRefCV>) {
|
|
910
|
+
return s;
|
|
911
|
+
} else if constexpr (std::is_pointer_v<DestNoRef>
|
|
912
|
+
&& !std::is_pointer_v<SrcD>) {
|
|
913
|
+
return &s;
|
|
914
|
+
} else {
|
|
915
|
+
return s;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
} // namespace detail
|
|
920
|
+
|
|
921
|
+
template<typename ToTuple, typename FromTuple, std::size_t... I>
|
|
922
|
+
inline ToTuple tuple_value_to_borrow_impl(FromTuple& t, std::index_sequence<I...>) {
|
|
923
|
+
return ToTuple(detail::borrow_value_elem<std::tuple_element_t<I, ToTuple>>(
|
|
924
|
+
std::get<I>(t))...);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// Convert a value-form source tuple (rvalue or lvalue) to a borrow-form
|
|
928
|
+
// destination tuple (T*, T&, or const T*-form slots). Used at tuple-literal
|
|
929
|
+
// sites whose target tuple has borrow-form slots and at least one literal
|
|
930
|
+
// element is an rvalue (e.g. `f((Point(1), 42))` where `f` takes a
|
|
931
|
+
// `tuple[Point | None, Int32]` or `tuple[Point, Int32]`).
|
|
932
|
+
//
|
|
933
|
+
// The caller materializes the source tuple as a temporary -- C++ extends
|
|
934
|
+
// its lifetime to the end of the surrounding full-expression, so the
|
|
935
|
+
// addresses / refs in the returned tuple stay valid through the call.
|
|
936
|
+
template<typename ToTuple, typename FromTuple>
|
|
937
|
+
inline ToTuple tuple_value_to_borrow(FromTuple&& t) {
|
|
938
|
+
using F = std::remove_reference_t<FromTuple>;
|
|
939
|
+
F& lref = t;
|
|
940
|
+
return tuple_value_to_borrow_impl<ToTuple>(
|
|
941
|
+
lref, std::make_index_sequence<std::tuple_size_v<F>>{});
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Default repr for records without __repr__/__str__: "<ClassName object at 0xADDR>"
|
|
945
|
+
template<typename T>
|
|
946
|
+
inline std::ostream& print_object_default(std::ostream& os, std::string_view class_name, const T& obj) {
|
|
947
|
+
auto flags = os.flags();
|
|
948
|
+
os << "<" << class_name << " object at 0x"
|
|
949
|
+
<< std::hex << reinterpret_cast<uintptr_t>(&obj) << ">";
|
|
950
|
+
os.flags(flags);
|
|
951
|
+
return os;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
} // namespace tpy
|