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,556 @@
|
|
|
1
|
+
# Writing TurboPython code (for coding agents)
|
|
2
|
+
|
|
3
|
+
This file is a bootstrap guide for coding agents writing TurboPython (TPy)
|
|
4
|
+
code in downstream projects. It assumes you already know Python; the goal is
|
|
5
|
+
to describe only the delta and the conventions that lead to idiomatic TPy.
|
|
6
|
+
|
|
7
|
+
For the full language reference, see `TPY_LANGUAGE_FEATURES.md` (shipped
|
|
8
|
+
alongside this file). Only sections marked **Working** are usable today --
|
|
9
|
+
treat **Planned** / **Open** as non-existent.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. What TurboPython is
|
|
14
|
+
|
|
15
|
+
TurboPython is a Python-to-C++ compiler. Source files are ordinary Python and
|
|
16
|
+
typically also run under CPython unchanged (dual-target), but are compiled to
|
|
17
|
+
C++ for performance. The compiler performs static type checking and produces
|
|
18
|
+
native binaries.
|
|
19
|
+
|
|
20
|
+
Why this matters for you as an agent writing code:
|
|
21
|
+
|
|
22
|
+
- Type-check statically: functions need parameter and return annotations;
|
|
23
|
+
incorrect types are errors, not runtime failures.
|
|
24
|
+
- Stay Python-idiomatic: most features you'd write in Python work the same
|
|
25
|
+
way. Reach for TPy-specific additions (`Own`, `Ptr`, `readonly`) only when
|
|
26
|
+
the semantics genuinely require them.
|
|
27
|
+
- `Own[T]` is a *semantic necessity* for some patterns (ownership transfer,
|
|
28
|
+
returning newly-created objects) -- it is not an optimisation knob.
|
|
29
|
+
- `Ptr[T]` and `readonly[T]` are *specialised tools*; well-written TPy
|
|
30
|
+
rarely uses them.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. Python -> TPy delta
|
|
35
|
+
|
|
36
|
+
The semantic gaps that actually bite when writing code:
|
|
37
|
+
|
|
38
|
+
- **Function signatures require type annotations.** Parameter types and the
|
|
39
|
+
return type are mandatory. Local variable types are usually inferred.
|
|
40
|
+
- **Classes with annotated attributes get inline field storage.** There is
|
|
41
|
+
no `__dict__`; you cannot add attributes not listed as annotations. If the
|
|
42
|
+
same file must also run under CPython, add an `__init__` that assigns each
|
|
43
|
+
field -- CPython doesn't create attributes from type annotations alone.
|
|
44
|
+
- **The `int` annotation means arbitrary precision (`BigInt`).** Use a
|
|
45
|
+
fixed-width type (`Int32`, `Int64`, ...) when you want machine integer
|
|
46
|
+
performance.
|
|
47
|
+
- **Untyped integer literals default to `Int32`** (configurable per
|
|
48
|
+
project via `--default-int=Int64|BigInt`). Plain `x = 5` infers as
|
|
49
|
+
`Int32`, not `BigInt`.
|
|
50
|
+
- **`str` is fine as a parameter type.** The compiler passes it as
|
|
51
|
+
`std::string_view` in parameters and stores it as `std::string` in fields.
|
|
52
|
+
You only need `StrView` / `String` / `Char` when you want explicit
|
|
53
|
+
control.
|
|
54
|
+
- **`None`-safety is enforced.** Optional values must be narrowed (`if x is
|
|
55
|
+
None` / `if x is not None`) before non-optional use.
|
|
56
|
+
- **Unions `A | B` are tagged variants.** Match them with `match`/`case`.
|
|
57
|
+
- **Ownership is explicit at a few specific boundaries** -- returning a
|
|
58
|
+
newly-created object, consuming a parameter, and storing into persistent
|
|
59
|
+
storage (fields, containers, globals). See section 5.
|
|
60
|
+
|
|
61
|
+
Everything else -- loops, comprehensions, f-strings, dicts, sets, tuples,
|
|
62
|
+
decorators, generators, match/case, context managers -- works like Python.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. Types at a glance
|
|
67
|
+
|
|
68
|
+
Import what you need from `tpy`; `from tpy import *` is acceptable for small
|
|
69
|
+
files. Core types:
|
|
70
|
+
|
|
71
|
+
| Category | Types |
|
|
72
|
+
|----------|-------|
|
|
73
|
+
| Numeric | `int` (BigInt), `Int8`/`Int16`/`Int32`/`Int64`, `UInt8`/`UInt16`/`UInt32`/`UInt64`, `float` / `Float64`, `Float32`, `bool` |
|
|
74
|
+
| Text | `str`, `StrView`, `String`, `Char`, `FStr` (parameter type that accepts an f-string without materialising a `str`) |
|
|
75
|
+
| Collections | `list[T]`, `dict[K, V]`, `set[T]`, `tuple[...]`, `Array[T, N]`, `Span[T]` |
|
|
76
|
+
| Bytes | `bytes`, `bytearray`, `BytesView` |
|
|
77
|
+
| Optional / union | `Optional[T]` / `T | None`, `A | B` |
|
|
78
|
+
| Ownership markers | `Own[T]`, `Ptr[T]`, `readonly[T]` |
|
|
79
|
+
|
|
80
|
+
When to reach for each:
|
|
81
|
+
|
|
82
|
+
- **`int` vs fixed-width**: use fixed-width (`Int32` / `Int64`) for
|
|
83
|
+
performance. Use `int` / `BigInt` only when you genuinely need arbitrary
|
|
84
|
+
precision -- it is much slower.
|
|
85
|
+
- **`list[T]`** is the default growable container, same role as in Python.
|
|
86
|
+
Use `Array[T, N]` for fixed-size stack-allocated arrays, `Span[T]` for
|
|
87
|
+
non-owning views into contiguous data.
|
|
88
|
+
- **`Optional[T]`** for "maybe-a-value" slots. `Ptr[T]` is already nullable,
|
|
89
|
+
so don't write `Ptr[T] | None` (the compiler warns and collapses it to
|
|
90
|
+
`Ptr[T]`). `T | None` for non-value `T` and `Ptr[T]` interconvert at
|
|
91
|
+
coercion boundaries (call args, returns, locals, field assignment) --
|
|
92
|
+
both lower to `T*` at borrow positions, and storage-form Optional
|
|
93
|
+
sources are lifted automatically when flowing into `Ptr[T]` slots.
|
|
94
|
+
|
|
95
|
+
### tplib at a glance
|
|
96
|
+
|
|
97
|
+
`tplib` ships TPy-native types that are too project-specific for the
|
|
98
|
+
language but common enough to standardize. Import as `from tplib import X`.
|
|
99
|
+
|
|
100
|
+
| Type | Use when |
|
|
101
|
+
|------|----------|
|
|
102
|
+
| `Box[T]` | You need a heap-allocated owning container -- e.g. recursive types, or oversized records you don't want stack-stored. Single owner. |
|
|
103
|
+
| `Rc[T]` | You need shared ownership (multiple owners of the same value, possibly with shared mutation). `@nocopy`; share via `.clone()`. Construct with `Rc.new(value)`. |
|
|
104
|
+
| `Weak[T]` | Non-owning companion to `Rc[T]`; breaks reference cycles. `from tplib.rc import Weak`. Mint via `rc.downgrade()`; recover a strong handle (or `None`) via `weak.upgrade()`. |
|
|
105
|
+
| `ArrayList[T, N]` | Fixed-capacity list with stack-allocated storage -- avoids heap allocation when the upper bound is known. |
|
|
106
|
+
| `FixStr[N]` | Fixed-capacity string with stack-allocated storage. |
|
|
107
|
+
| `tplib.json` | JSON decoding/encoding via a `@model` class macro. |
|
|
108
|
+
|
|
109
|
+
For full details (semantics, tradeoffs, current rough edges), see
|
|
110
|
+
`LANGUAGE_FEATURES.md`.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 4. Integer conventions
|
|
115
|
+
|
|
116
|
+
- Default fixed-int is **`Int32`** unless the downstream project configures
|
|
117
|
+
`--default-int` otherwise. Check the project's build config (or just try
|
|
118
|
+
compiling a snippet with a literal) before assuming.
|
|
119
|
+
- Prefer `Int32` for counters, loop variables, and small counts.
|
|
120
|
+
- Use `Int64` when you might plausibly exceed 2 billion (byte counts on
|
|
121
|
+
large data, timestamps in nanoseconds, etc.).
|
|
122
|
+
- Use `int` / `BigInt` only when unbounded precision is required.
|
|
123
|
+
- Do not sprinkle `Int32(...)` constructors -- trust inference and write
|
|
124
|
+
plain literals (`x = 5`, `xs = [1, 2, 3]`). Explicit constructors are
|
|
125
|
+
only needed when the inferred type would otherwise be wrong.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 5. Ownership and references
|
|
130
|
+
|
|
131
|
+
This is the one section where TPy semantics differ from CPython in
|
|
132
|
+
important ways. Read it once; most code you write afterwards will be
|
|
133
|
+
plain-`T` and the ownership markers will stay out of your way.
|
|
134
|
+
|
|
135
|
+
### 5.1 Mental model
|
|
136
|
+
|
|
137
|
+
In CPython, every variable is a reference to a heap object. TPy keeps that
|
|
138
|
+
behavior for **locals and parameters** (so `y = x` and `f(x)` behave the
|
|
139
|
+
same way as in Python), but differs for **persistent storage** -- fields,
|
|
140
|
+
list/dict/set elements, globals -- which *own* their values rather than
|
|
141
|
+
sharing references.
|
|
142
|
+
|
|
143
|
+
This single change (storage owns values) is the root of every ownership
|
|
144
|
+
rule below. Value types (`Int32`, `bool`, `float`, `str`, `Char`, ...) are
|
|
145
|
+
unaffected: they copy silently and never need `Own`.
|
|
146
|
+
|
|
147
|
+
The compiler internally distinguishes two C++ shapes for non-value types:
|
|
148
|
+
**storage form** at owned slots (fields, container elements, `Own[T]`
|
|
149
|
+
params, returns) and **borrow form** at non-owning slots (regular params,
|
|
150
|
+
locals, iterator yields). You rarely think about this directly --
|
|
151
|
+
ownership annotations like `Own[T]` and the copy warnings below are the
|
|
152
|
+
user-facing surface. The terms appear in compiler diagnostics ("borrowed
|
|
153
|
+
Optional/Union", "storage-form source"); `TPY_LANGUAGE_FEATURES.md` has
|
|
154
|
+
the full definition if you need it.
|
|
155
|
+
|
|
156
|
+
### 5.2 Plain `T` is the default -- use it almost everywhere
|
|
157
|
+
|
|
158
|
+
- **Parameters**: `def f(x: MyRecord) -> ...` -- passed by reference.
|
|
159
|
+
Non-mutating parameters are auto-downgraded to const-reference.
|
|
160
|
+
- **Locals**: `y = x` aliases the same object, exactly like Python.
|
|
161
|
+
- **Returning references to caller-owned data** (e.g. an element of a list
|
|
162
|
+
parameter): plain `T`.
|
|
163
|
+
- **Value types**: always plain. Never wrap `Int32` or `str` in `Own`.
|
|
164
|
+
|
|
165
|
+
### 5.3 When you need `Own[T]`
|
|
166
|
+
|
|
167
|
+
Three concrete triggers:
|
|
168
|
+
|
|
169
|
+
**(a) Returning a newly-created object.** Factory functions, constructors
|
|
170
|
+
that produce fresh values. The compiler is free to put the value on the
|
|
171
|
+
stack or the heap; what matters is that the caller now owns it.
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
def make_point(x: Int32, y: Int32) -> Own[Point]:
|
|
175
|
+
return Point(x, y)
|
|
176
|
+
|
|
177
|
+
def load_config(path: str) -> Own[Config]:
|
|
178
|
+
...
|
|
179
|
+
return Config(...)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The same applies element-wise inside a returned tuple: a function
|
|
183
|
+
typed `-> tuple[str, Point]` is rejected (the `Point` element looks
|
|
184
|
+
like return-by-reference and the constructor temporary doesn't
|
|
185
|
+
outlive the return). Spell it `-> tuple[str, Own[Point]]` -- the
|
|
186
|
+
`Own[T]` rule applies per slot:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
def find(p: Point) -> tuple[str, Own[Point]]:
|
|
190
|
+
return ("found", Point(p.x + 1, p.y))
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This is the most common stumbling block when porting Python code that
|
|
194
|
+
returns multiple results bundled in a tuple.
|
|
195
|
+
|
|
196
|
+
**(b) A parameter that consumes its argument.** Use `Own[T]` for a
|
|
197
|
+
parameter when the function takes ownership of the value -- typically when
|
|
198
|
+
storing it into a long-lived container.
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
def adopt(self, dog: Own[Dog]) -> None:
|
|
202
|
+
self.kennel.append(dog) # dog is consumed
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
If the caller's variable isn't used after the call, the compiler
|
|
206
|
+
auto-moves silently (see 5.5). If it *is* used afterwards, the compiler
|
|
207
|
+
copies and emits the warning from 5.4 -- the variable stays usable, but
|
|
208
|
+
you've paid for a copy.
|
|
209
|
+
|
|
210
|
+
**(c) Fields, list/dict/set elements, global variables.** These own their
|
|
211
|
+
values; this is the default. You write the field type as plain `T`
|
|
212
|
+
(`kennel: list[Dog]`), not `list[Own[Dog]]` -- ownership is implied by
|
|
213
|
+
storage.
|
|
214
|
+
|
|
215
|
+
### 5.4 CPython divergence and `copy()`
|
|
216
|
+
|
|
217
|
+
The compiler issues a warning when it would emit a copy that CPython would
|
|
218
|
+
*not* emit (CPython would share a reference instead). You fix it by making
|
|
219
|
+
the copy explicit with `copy` from `tpy`:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from tpy import copy
|
|
223
|
+
|
|
224
|
+
def remember(self, dog: Dog) -> None:
|
|
225
|
+
self.last_seen = copy(dog) # explicit; both runtimes now match
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The warning fires when a non-value-type lvalue (parameter, owned local
|
|
229
|
+
that's still alive afterwards, borrowed Optional/Union) is used as the
|
|
230
|
+
source of:
|
|
231
|
+
|
|
232
|
+
- A field assignment (`self.x = other`).
|
|
233
|
+
- A container op (`xs.append(other)`, `xs[i] = other`, `d[k] = other`,
|
|
234
|
+
`d.update(other)`).
|
|
235
|
+
- An argument passed into an `Own[T]` parameter.
|
|
236
|
+
- A global assignment.
|
|
237
|
+
|
|
238
|
+
It does **not** fire when:
|
|
239
|
+
|
|
240
|
+
- The source is an rvalue (e.g. `xs.append(Point(1, 2))`).
|
|
241
|
+
- The source is a value type (`Int32`, `bool`, `float`, `str`, `Char`,
|
|
242
|
+
...).
|
|
243
|
+
- The source is at its last use (auto-move kicks in silently -- see 5.5).
|
|
244
|
+
|
|
245
|
+
Three ways to resolve the warning, in order of preference:
|
|
246
|
+
|
|
247
|
+
1. **Restructure so the source is dead afterwards** -- auto-move takes over
|
|
248
|
+
and no `copy()` is needed.
|
|
249
|
+
2. **Construct fresh at the assignment site** -- rvalues never warn.
|
|
250
|
+
3. **Wrap the source with `copy(...)`** when you genuinely need both the
|
|
251
|
+
original and a copy.
|
|
252
|
+
|
|
253
|
+
For iterating a container with per-element copies, there is a related
|
|
254
|
+
warning suggesting `copy_iter()` (copy each element on iteration) or
|
|
255
|
+
`copy()` (copy the whole container up front) -- pick based on which
|
|
256
|
+
behaviour you actually want.
|
|
257
|
+
|
|
258
|
+
This warning exists precisely so that dual-target code behaves identically
|
|
259
|
+
under CPython and the compiled binary. Never silence it without
|
|
260
|
+
understanding which path you want.
|
|
261
|
+
|
|
262
|
+
### 5.5 Auto-move at last use
|
|
263
|
+
|
|
264
|
+
You do not write `std::move` / explicit consume markers. When a variable
|
|
265
|
+
isn't used after being passed to an `Own[T]` parameter, the compiler moves
|
|
266
|
+
it automatically (no warning). If it *is* used after, the compiler copies
|
|
267
|
+
(with the warning from 5.4).
|
|
268
|
+
|
|
269
|
+
Structure code so ownership hand-off is the last use of the variable, and
|
|
270
|
+
you'll almost never see copy warnings.
|
|
271
|
+
|
|
272
|
+
### 5.6 `Ptr[T]` -- non-owning pointers stored in structures
|
|
273
|
+
|
|
274
|
+
The main valid use case is a structure that holds a reference to another
|
|
275
|
+
structure it doesn't own: back-pointers, observer lists, graph edges, cache
|
|
276
|
+
entries pointing into a larger data structure.
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
class Node:
|
|
280
|
+
parent: Ptr[Node] # already nullable; assign None to clear
|
|
281
|
+
children: list[Node]
|
|
282
|
+
|
|
283
|
+
root = Node()
|
|
284
|
+
child = Node()
|
|
285
|
+
child.parent = root # plain assignment; no take_ptr() needed
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`Ptr[T]` is always nullable; assign `None` to clear. Null dereferences are
|
|
289
|
+
checked at runtime.
|
|
290
|
+
|
|
291
|
+
Do **not** reach for `Ptr[T]` for:
|
|
292
|
+
- Function parameters -- plain `T` is better.
|
|
293
|
+
- Optional-by-reference -- use `Optional[T]`.
|
|
294
|
+
- Returning new values -- use `Own[T]`.
|
|
295
|
+
- Returning a reference to caller-owned data -- plain `T`.
|
|
296
|
+
|
|
297
|
+
For most assignments into `Ptr` fields or arguments, plain assignment
|
|
298
|
+
works (the compiler inserts an implicit address-of coercion, as in the
|
|
299
|
+
TreeNode example above). `take_ptr(x)` exists for the case where you want
|
|
300
|
+
to bind an explicit `Ptr[T]` *local variable* (or interop with native
|
|
301
|
+
code) and need to materialise the pointer yourself; you will almost
|
|
302
|
+
certainly never need it.
|
|
303
|
+
|
|
304
|
+
### 5.7 `readonly[T]` -- mostly compiler-inferred
|
|
305
|
+
|
|
306
|
+
The compiler infers const-ness automatically from your code's mutation
|
|
307
|
+
patterns (non-mutating parameters become const-ref, etc.). You write
|
|
308
|
+
`readonly[T]` explicitly in two situations:
|
|
309
|
+
|
|
310
|
+
- **C++ interop signatures**, where the mapping to `const T*` /
|
|
311
|
+
`std::span<const T>` must be explicit.
|
|
312
|
+
- **Communicating intent on spans or pointers**: `Span[readonly[T]]`,
|
|
313
|
+
`Ptr[readonly[T]]`.
|
|
314
|
+
|
|
315
|
+
In pure-TPy code you rarely write it by hand.
|
|
316
|
+
|
|
317
|
+
### 5.8 Advanced: consuming iteration
|
|
318
|
+
|
|
319
|
+
When you iterate a container that's at its last use, the compiler
|
|
320
|
+
automatically switches to consuming iteration -- elements are moved out
|
|
321
|
+
of the source rather than copied. You don't need to write anything
|
|
322
|
+
special:
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from tpy import Own
|
|
326
|
+
|
|
327
|
+
def drain() -> Own[list[Widget]]:
|
|
328
|
+
src: list[Widget] = [Widget("a"), Widget("b")]
|
|
329
|
+
dst: list[Widget] = []
|
|
330
|
+
for w in src: # src is dead after this loop -> auto-consumed
|
|
331
|
+
dst.append(w) # w is moved into dst, no copy warning
|
|
332
|
+
return dst
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
If you need to force consuming iteration even when the source might be
|
|
336
|
+
used afterwards, wrap with `own_iter()` from `tpy` -- this consumes the
|
|
337
|
+
source explicitly. Reach for it only when you specifically need that
|
|
338
|
+
behaviour; the auto-consuming case above is fine almost always.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## 6. Writing idiomatic TPy
|
|
343
|
+
|
|
344
|
+
- **Annotate function signatures; let the compiler infer locals.** Only
|
|
345
|
+
annotate a local when inference would pick the wrong type.
|
|
346
|
+
- **Prefer plain literals** (`1`, `"hello"`, `{1, 2}`) over explicit
|
|
347
|
+
constructors and variable annotations.
|
|
348
|
+
- **Put logic inside functions**, not at module top level. Top-level code
|
|
349
|
+
uses a different codegen path (globals as pointer slots); keep top-level
|
|
350
|
+
to imports, constants, and a single `main()` call.
|
|
351
|
+
- **Use `match`/`case` for unions and enums.** It's the idiomatic dispatch
|
|
352
|
+
form in TPy.
|
|
353
|
+
- **Narrow `Optional[T]` explicitly** with `if x is None` / `if x is not
|
|
354
|
+
None` before non-optional use.
|
|
355
|
+
- **Prefer protocols over inheritance.** Protocols are structural; they
|
|
356
|
+
don't require class hierarchies.
|
|
357
|
+
- **Keep `@native` / `@export` in a dedicated interop module**, not
|
|
358
|
+
scattered across regular code.
|
|
359
|
+
- **Read copy warnings; don't suppress them.** They flag real CPython / TPy
|
|
360
|
+
semantic divergences.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 7. Worked examples
|
|
365
|
+
|
|
366
|
+
Only the things that differ from Python or that agents commonly get wrong.
|
|
367
|
+
|
|
368
|
+
**Record with fields and methods.**
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
from tpy import Int32
|
|
372
|
+
|
|
373
|
+
class Point:
|
|
374
|
+
x: Int32
|
|
375
|
+
y: Int32
|
|
376
|
+
|
|
377
|
+
def __init__(self, x: Int32, y: Int32) -> None:
|
|
378
|
+
self.x = x
|
|
379
|
+
self.y = y
|
|
380
|
+
|
|
381
|
+
def distance_sq(self, other: Point) -> Int32:
|
|
382
|
+
dx = self.x - other.x
|
|
383
|
+
dy = self.y - other.y
|
|
384
|
+
return dx * dx + dy * dy
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Factory returning `Own`.**
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
from tpy import Own
|
|
391
|
+
|
|
392
|
+
def make_origin() -> Own[Point]:
|
|
393
|
+
return Point(0, 0)
|
|
394
|
+
|
|
395
|
+
def main() -> None:
|
|
396
|
+
p = make_origin()
|
|
397
|
+
print(p.x, p.y)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Union and `match`.**
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
class Cat:
|
|
404
|
+
name: str
|
|
405
|
+
def __init__(self, name: str) -> None: self.name = name
|
|
406
|
+
|
|
407
|
+
class Dog:
|
|
408
|
+
name: str
|
|
409
|
+
def __init__(self, name: str) -> None: self.name = name
|
|
410
|
+
|
|
411
|
+
def describe(animal: Cat | Dog) -> str:
|
|
412
|
+
match animal:
|
|
413
|
+
case Cat():
|
|
414
|
+
return f"a cat named {animal.name}"
|
|
415
|
+
case Dog():
|
|
416
|
+
return f"a dog named {animal.name}"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**`Optional` narrowing.**
|
|
420
|
+
|
|
421
|
+
```python
|
|
422
|
+
def greet(name: str | None) -> None:
|
|
423
|
+
if name is None:
|
|
424
|
+
print("hello, stranger")
|
|
425
|
+
return
|
|
426
|
+
print("hello,", name) # here name: str
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Generic function with a protocol bound.**
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
from tpy import Comparable # builtin protocol: defines __lt__(self, other: Self)
|
|
433
|
+
|
|
434
|
+
def maximum[T: Comparable](a: T, b: T) -> T:
|
|
435
|
+
if a < b:
|
|
436
|
+
return b
|
|
437
|
+
return a
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
For user-defined protocols, use `Self` from `typing` for methods that
|
|
441
|
+
reference the implementing type (so the bound `T` propagates correctly):
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from typing import Protocol, Self
|
|
445
|
+
from tpy import Own
|
|
446
|
+
|
|
447
|
+
class Clonable(Protocol):
|
|
448
|
+
def clone(self) -> Own[Self]: ...
|
|
449
|
+
|
|
450
|
+
def clone_it[T: Clonable](item: T) -> Own[T]:
|
|
451
|
+
return item.clone()
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Non-owning back-pointer.**
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
from tpy import Ptr, Own
|
|
458
|
+
|
|
459
|
+
class TreeNode:
|
|
460
|
+
value: Int32
|
|
461
|
+
parent: Ptr[TreeNode]
|
|
462
|
+
children: list[TreeNode]
|
|
463
|
+
|
|
464
|
+
def __init__(self, value: Int32) -> None:
|
|
465
|
+
self.value = value
|
|
466
|
+
self.parent = None
|
|
467
|
+
self.children = []
|
|
468
|
+
|
|
469
|
+
# Own[TreeNode]: the tree takes ownership of the child so the
|
|
470
|
+
# subsequent append() doesn't trigger a copy warning. The caller's
|
|
471
|
+
# variable is auto-moved at last use (see 5.5).
|
|
472
|
+
def add_child(self, child: Own[TreeNode]) -> None:
|
|
473
|
+
child.parent = self
|
|
474
|
+
self.children.append(child)
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Explicit `copy()` on field assignment.**
|
|
478
|
+
|
|
479
|
+
```python
|
|
480
|
+
from tpy import copy
|
|
481
|
+
|
|
482
|
+
class Cache:
|
|
483
|
+
last: Point
|
|
484
|
+
|
|
485
|
+
def remember(self, p: Point) -> None:
|
|
486
|
+
self.last = copy(p) # acknowledged copy; warning gone
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 8. Verifying your code
|
|
492
|
+
|
|
493
|
+
Compile and run a snippet with the downstream project's `tpy` invocation
|
|
494
|
+
(this varies per project -- check its README or AGENTS.md for the exact
|
|
495
|
+
command). A typical form:
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
tpy path/to/snippet.py # compile + run
|
|
499
|
+
tpy --dump-code path/to/snippet.py # print generated C++
|
|
500
|
+
tpy -O path/to/snippet.py # release build
|
|
501
|
+
tpy --print-types # list every public type/function from lib/tpy/
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
`tpy --print-types` dumps a markdown reference with a TOC and every
|
|
505
|
+
record/protocol/function signature available in the `tpy`, `tplib`,
|
|
506
|
+
`typing`, and standard-library stubs. Useful when you need to confirm a
|
|
507
|
+
method exists, check a signature, or look up a protocol before writing
|
|
508
|
+
code. Pipe to `glow -p` for a nice terminal view.
|
|
509
|
+
|
|
510
|
+
Diagnostics are line-precise and usually name the fix. When a type error
|
|
511
|
+
is confusing, inspect the generated C++ with `--dump-code` -- the mapping
|
|
512
|
+
is usually clear enough to spot what the compiler inferred.
|
|
513
|
+
|
|
514
|
+
If the code must also run under CPython (dual-target), run it with
|
|
515
|
+
`python` as well and confirm output matches. CPython reference-shares
|
|
516
|
+
values that TPy copies; that's exactly what the `copy()` warnings from 5.4
|
|
517
|
+
exist to prevent diverging on.
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## 9. Current limitations (may be lifted)
|
|
522
|
+
|
|
523
|
+
The compiler is under active development. The following features are not
|
|
524
|
+
yet available but are on the roadmap:
|
|
525
|
+
|
|
526
|
+
- `async` / `await`.
|
|
527
|
+
- Stepped slice assignment (`items[::2] = [...]`).
|
|
528
|
+
- Dynamic attribute creation on compiled records (`setattr` or assigning
|
|
529
|
+
to undeclared fields) -- today, fields must appear as class-level
|
|
530
|
+
annotations.
|
|
531
|
+
|
|
532
|
+
If you're tempted to use one of these, pick the closest synchronous /
|
|
533
|
+
fully-annotated equivalent and leave a comment noting the dependency.
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## 10. Where to go next
|
|
538
|
+
|
|
539
|
+
For the full language reference, see `TPY_LANGUAGE_FEATURES.md` (shipped
|
|
540
|
+
alongside this file). Only trust sections marked **Working**.
|
|
541
|
+
|
|
542
|
+
For the exact list of types, functions, and protocols available from
|
|
543
|
+
`tpy`, `tplib`, `typing`, and the standard-library stubs, run `tpy
|
|
544
|
+
--print-types`. This is the authoritative surface -- if it's not
|
|
545
|
+
there, it's not exposed.
|
|
546
|
+
|
|
547
|
+
Topics worth looking up there when you need depth beyond this guide:
|
|
548
|
+
|
|
549
|
+
- Ownership edge cases, escape analysis, move semantics.
|
|
550
|
+
- `Optional` narrowing rules and flow-sensitive analysis.
|
|
551
|
+
- `match`/`case` patterns (literal, record, union, optional, enum, guard,
|
|
552
|
+
or-pattern, positional).
|
|
553
|
+
- Union types (variant codegen, recursive unions).
|
|
554
|
+
- `@native` / `@export` native interop for C++ bindings.
|
|
555
|
+
- `@error_return` zero-cost error handling.
|
|
556
|
+
- Protocol definition and conformance.
|