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
tpyc/macro_loader.py
ADDED
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Macro Module Loader
|
|
3
|
+
|
|
4
|
+
Discovers and loads ``# tpy: macro_module`` files via CPython during
|
|
5
|
+
compilation. Macro modules are NOT compiled to C++ -- they run at compile
|
|
6
|
+
time only.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import importlib.util
|
|
12
|
+
import inspect
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
import typing
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any, Callable
|
|
18
|
+
|
|
19
|
+
import builtins as _builtins_module
|
|
20
|
+
|
|
21
|
+
from . import macro_api as _macro_api
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Macro module import/builtin restrictions
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Soft restrictions to keep macro modules on the stable tpyc.macro_api surface.
|
|
28
|
+
# NOT a security sandbox -- Python cannot be fully sandboxed via __builtins__.
|
|
29
|
+
# The goal is forward compatibility: when the compiler is self-hosted, macro
|
|
30
|
+
# code will run in a VM where only the macro_api surface is available.
|
|
31
|
+
|
|
32
|
+
# Modules that macro code is allowed to import.
|
|
33
|
+
_ALLOWED_IMPORTS: frozenset[str] = frozenset({
|
|
34
|
+
"tpyc.macro_api",
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
# Builtins that are NOT available in macro modules.
|
|
38
|
+
_BLOCKED_BUILTINS: frozenset[str] = frozenset({
|
|
39
|
+
"open", "exec", "eval", "compile",
|
|
40
|
+
"input", "breakpoint", "exit", "quit",
|
|
41
|
+
"memoryview",
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
_original_import = _builtins_module.__import__
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _make_restricted_import(
|
|
48
|
+
module_name: str, registry: "MacroRegistry",
|
|
49
|
+
) -> Callable:
|
|
50
|
+
"""Create a restricted __import__ for a macro module."""
|
|
51
|
+
def _restricted_import(name: str, *args: Any, **kwargs: Any) -> Any:
|
|
52
|
+
if not name:
|
|
53
|
+
raise ImportError(
|
|
54
|
+
f"Macro module '{module_name}' cannot use relative imports"
|
|
55
|
+
)
|
|
56
|
+
for allowed in _ALLOWED_IMPORTS:
|
|
57
|
+
if name == allowed or name.startswith(allowed + "."):
|
|
58
|
+
return _original_import(name, *args, **kwargs)
|
|
59
|
+
# Try resolving as another macro module from lib search paths
|
|
60
|
+
mod = registry._resolve_macro_import(name)
|
|
61
|
+
if mod is not None:
|
|
62
|
+
return mod
|
|
63
|
+
raise ImportError(
|
|
64
|
+
f"Macro module '{module_name}' cannot import '{name}' "
|
|
65
|
+
f"-- only tpyc.macro_api and other macro modules are allowed"
|
|
66
|
+
)
|
|
67
|
+
return _restricted_import
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _make_restricted_builtins(
|
|
71
|
+
module_name: str, registry: "MacroRegistry",
|
|
72
|
+
) -> dict[str, Any]:
|
|
73
|
+
"""Create a restricted __builtins__ dict for a macro module."""
|
|
74
|
+
restricted = {
|
|
75
|
+
k: v for k, v in _builtins_module.__dict__.items()
|
|
76
|
+
if k not in _BLOCKED_BUILTINS
|
|
77
|
+
}
|
|
78
|
+
restricted["__import__"] = _make_restricted_import(module_name, registry)
|
|
79
|
+
return restricted
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
_MACRO_MODULE_RE = re.compile(r'^\s*#\s*tpy:\s+macro_module\s*$')
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def is_macro_module_source(source: str) -> bool:
|
|
86
|
+
"""Quick check whether source text contains ``# tpy: macro_module``."""
|
|
87
|
+
# Only scan the preamble (before first non-comment, non-blank line)
|
|
88
|
+
for line in source.splitlines():
|
|
89
|
+
stripped = line.strip()
|
|
90
|
+
if stripped and not stripped.startswith('#'):
|
|
91
|
+
break
|
|
92
|
+
if _MACRO_MODULE_RE.match(line):
|
|
93
|
+
return True
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def call_macro_field_function(
|
|
98
|
+
registry: Any,
|
|
99
|
+
call: Any,
|
|
100
|
+
loc: Any,
|
|
101
|
+
) -> Any | None:
|
|
102
|
+
"""Call a macro-module function from a field default and return the result.
|
|
103
|
+
|
|
104
|
+
If the call's resolved_import points to a loaded macro module, looks up
|
|
105
|
+
the function, extracts kwargs, and calls it. Returns None if not resolvable.
|
|
106
|
+
"""
|
|
107
|
+
from .diagnostics import SemanticError
|
|
108
|
+
|
|
109
|
+
resolved = getattr(call, 'resolved_import', None)
|
|
110
|
+
if resolved is None:
|
|
111
|
+
return None
|
|
112
|
+
mod_name, func_name = resolved
|
|
113
|
+
func = registry.get_export(mod_name, func_name)
|
|
114
|
+
if func is None:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
if call.args:
|
|
118
|
+
raise SemanticError(
|
|
119
|
+
f"{func_name}() does not accept positional arguments", loc)
|
|
120
|
+
|
|
121
|
+
# Unwrap literal kwargs to plain Python values so macro field functions
|
|
122
|
+
# see the same types in both compiler and CPython paths.
|
|
123
|
+
from .parse import (
|
|
124
|
+
TpyStrLiteral, TpyIntLiteral, TpyFloatLiteral, TpyBoolLiteral, TpyNoneLiteral,
|
|
125
|
+
)
|
|
126
|
+
kwargs = {}
|
|
127
|
+
for k, v in call.kwargs.items():
|
|
128
|
+
if isinstance(v, TpyBoolLiteral):
|
|
129
|
+
kwargs[k] = v.value
|
|
130
|
+
elif isinstance(v, (TpyIntLiteral, TpyFloatLiteral, TpyStrLiteral)):
|
|
131
|
+
kwargs[k] = v.value
|
|
132
|
+
elif isinstance(v, TpyNoneLiteral):
|
|
133
|
+
kwargs[k] = None
|
|
134
|
+
else:
|
|
135
|
+
kwargs[k] = v # non-literal (e.g. TpyName for default_factory)
|
|
136
|
+
try:
|
|
137
|
+
return func(**kwargs)
|
|
138
|
+
except TypeError as e:
|
|
139
|
+
raise SemanticError(f"{func_name}(): {e}", loc) from e
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def validate_and_call_macro(
|
|
143
|
+
macro_fn: Callable,
|
|
144
|
+
cls_info: Any,
|
|
145
|
+
kwargs: dict[str, Any],
|
|
146
|
+
macro_name: str,
|
|
147
|
+
loc: Any,
|
|
148
|
+
) -> None:
|
|
149
|
+
"""Validate kwargs against macro signature and invoke the macro.
|
|
150
|
+
|
|
151
|
+
Inspects the macro function's signature to check for unknown kwargs,
|
|
152
|
+
missing required kwargs, and type mismatches. Wraps errors as
|
|
153
|
+
SemanticError with the decorator's source location.
|
|
154
|
+
"""
|
|
155
|
+
# Deferred: sema.registration imports macro_loader, so importing
|
|
156
|
+
# diagnostics at module level would create a circular import.
|
|
157
|
+
from .diagnostics import SemanticError
|
|
158
|
+
|
|
159
|
+
sig = inspect.signature(macro_fn)
|
|
160
|
+
params = sig.parameters
|
|
161
|
+
|
|
162
|
+
# Skip the first parameter (cls: ClassInfo)
|
|
163
|
+
param_list = list(params.values())
|
|
164
|
+
if not param_list:
|
|
165
|
+
raise SemanticError(
|
|
166
|
+
f"@{macro_name}: macro function must accept a ClassInfo parameter",
|
|
167
|
+
loc,
|
|
168
|
+
)
|
|
169
|
+
_SKIP_KINDS = (inspect.Parameter.VAR_KEYWORD, inspect.Parameter.VAR_POSITIONAL)
|
|
170
|
+
macro_params = {p.name: p for p in param_list[1:] if p.kind not in _SKIP_KINDS}
|
|
171
|
+
|
|
172
|
+
# Check for **kwargs -- if present, skip unknown-kwarg validation
|
|
173
|
+
has_var_keyword = any(
|
|
174
|
+
p.kind == inspect.Parameter.VAR_KEYWORD for p in param_list[1:]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Reject unknown kwargs
|
|
178
|
+
if not has_var_keyword:
|
|
179
|
+
for key in kwargs:
|
|
180
|
+
if key not in macro_params:
|
|
181
|
+
if macro_params:
|
|
182
|
+
known = "(supported: " + ", ".join(sorted(macro_params)) + ")"
|
|
183
|
+
else:
|
|
184
|
+
known = "(takes no keyword arguments)"
|
|
185
|
+
raise SemanticError(
|
|
186
|
+
f"@{macro_name}: unknown keyword argument '{key}' {known}",
|
|
187
|
+
loc,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Check for missing required kwargs (no default value)
|
|
191
|
+
for name, param in macro_params.items():
|
|
192
|
+
if param.default is inspect.Parameter.empty and name not in kwargs:
|
|
193
|
+
raise SemanticError(
|
|
194
|
+
f"@{macro_name}: missing required keyword argument '{name}'",
|
|
195
|
+
loc,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Resolve annotations (handles `from __future__ import annotations`
|
|
199
|
+
# which turns annotations into strings at runtime)
|
|
200
|
+
try:
|
|
201
|
+
hints = typing.get_type_hints(macro_fn)
|
|
202
|
+
except Exception:
|
|
203
|
+
hints = {}
|
|
204
|
+
|
|
205
|
+
# Type-check values against annotations
|
|
206
|
+
for key, value in kwargs.items():
|
|
207
|
+
if key not in macro_params:
|
|
208
|
+
continue
|
|
209
|
+
ann = hints.get(key)
|
|
210
|
+
if ann is None:
|
|
211
|
+
continue
|
|
212
|
+
if not isinstance(ann, type):
|
|
213
|
+
continue
|
|
214
|
+
if not isinstance(value, ann):
|
|
215
|
+
raise SemanticError(
|
|
216
|
+
f"@{macro_name}: '{key}' must be {ann.__name__}, "
|
|
217
|
+
f"got {type(value).__name__} ({value!r})",
|
|
218
|
+
loc,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Call the macro, wrapping unexpected exceptions
|
|
222
|
+
from .macro_api import MacroError, ast as _ast_builder
|
|
223
|
+
|
|
224
|
+
_ast_builder.reset_tmp_counter()
|
|
225
|
+
try:
|
|
226
|
+
macro_fn(cls_info, **kwargs)
|
|
227
|
+
except MacroError as e:
|
|
228
|
+
raise SemanticError(str(e), e.loc or loc) from e
|
|
229
|
+
except SemanticError:
|
|
230
|
+
raise
|
|
231
|
+
except Exception as e:
|
|
232
|
+
raise SemanticError(
|
|
233
|
+
f"@{macro_name}: macro raised {type(e).__name__}: {e}",
|
|
234
|
+
loc,
|
|
235
|
+
) from e
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
_EXTRACTABLE_TYPES = (str, int, float, bool)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _extract_macro_arg_value(macro_arg: Any, expected_type: type, param_name: str,
|
|
242
|
+
macro_name: str, loc: Any) -> Any:
|
|
243
|
+
"""Extract a Python value from a MacroArg for simple-typed parameters."""
|
|
244
|
+
from .diagnostics import SemanticError
|
|
245
|
+
from .parse import TpyStrLiteral, TpyIntLiteral, TpyFloatLiteral, TpyBoolLiteral
|
|
246
|
+
|
|
247
|
+
expr = macro_arg.expr
|
|
248
|
+
_LITERAL_MAP = {
|
|
249
|
+
str: (TpyStrLiteral, "a string literal"),
|
|
250
|
+
int: (TpyIntLiteral, "an integer literal"),
|
|
251
|
+
float: (TpyFloatLiteral, "a float literal"),
|
|
252
|
+
bool: (TpyBoolLiteral, "a boolean literal"),
|
|
253
|
+
}
|
|
254
|
+
literal_type, desc = _LITERAL_MAP[expected_type]
|
|
255
|
+
if not isinstance(expr, literal_type):
|
|
256
|
+
raise SemanticError(
|
|
257
|
+
f"{macro_name}(): '{param_name}' must be {desc}", loc)
|
|
258
|
+
return expr.value
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def expand_call_macro(
|
|
262
|
+
macro_fn: Callable,
|
|
263
|
+
ctx: Any,
|
|
264
|
+
macro_args: list,
|
|
265
|
+
macro_kwargs: dict,
|
|
266
|
+
macro_name: str,
|
|
267
|
+
loc: Any,
|
|
268
|
+
) -> Any:
|
|
269
|
+
"""Validate args and call a call-site macro, returning the replacement TpyExpr.
|
|
270
|
+
|
|
271
|
+
Kwargs annotated with simple types (str, int, float, bool) are extracted
|
|
272
|
+
from the MacroArg automatically. Wraps unexpected exceptions as SemanticError.
|
|
273
|
+
"""
|
|
274
|
+
# Deferred: sema.registration imports macro_loader
|
|
275
|
+
from .diagnostics import SemanticError
|
|
276
|
+
from .macro_api import MacroError, ast as _ast_builder
|
|
277
|
+
|
|
278
|
+
_ast_builder.reset_tmp_counter()
|
|
279
|
+
|
|
280
|
+
# Inspect signature: extract plain values for simple-typed kwargs
|
|
281
|
+
sig = inspect.signature(macro_fn)
|
|
282
|
+
params = list(sig.parameters.values())
|
|
283
|
+
resolved_kwargs: dict[str, Any] = {}
|
|
284
|
+
try:
|
|
285
|
+
hints = typing.get_type_hints(macro_fn)
|
|
286
|
+
except Exception:
|
|
287
|
+
hints = {}
|
|
288
|
+
for key, macro_arg in macro_kwargs.items():
|
|
289
|
+
ann = hints.get(key)
|
|
290
|
+
if isinstance(ann, type) and ann in _EXTRACTABLE_TYPES:
|
|
291
|
+
resolved_kwargs[key] = _extract_macro_arg_value(
|
|
292
|
+
macro_arg, ann, key, macro_name, loc)
|
|
293
|
+
else:
|
|
294
|
+
resolved_kwargs[key] = macro_arg
|
|
295
|
+
|
|
296
|
+
try:
|
|
297
|
+
result = macro_fn(ctx, *macro_args, **resolved_kwargs)
|
|
298
|
+
except MacroError as e:
|
|
299
|
+
raise SemanticError(str(e), e.loc or loc) from e
|
|
300
|
+
except SemanticError:
|
|
301
|
+
raise
|
|
302
|
+
except Exception as e:
|
|
303
|
+
raise SemanticError(
|
|
304
|
+
f"{macro_name}(): macro raised {type(e).__name__}: {e}",
|
|
305
|
+
loc,
|
|
306
|
+
) from e
|
|
307
|
+
|
|
308
|
+
from .parse import TpyExpr
|
|
309
|
+
if not isinstance(result, TpyExpr):
|
|
310
|
+
raise SemanticError(
|
|
311
|
+
f"{macro_name}(): call macro must return a TpyExpr, "
|
|
312
|
+
f"got {type(result).__name__}",
|
|
313
|
+
loc,
|
|
314
|
+
)
|
|
315
|
+
return result
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _wrap_macro_call(
|
|
319
|
+
fn: Callable, what: str, loc: Any, args: tuple, kwargs: dict,
|
|
320
|
+
) -> Any:
|
|
321
|
+
"""Invoke a builder-macro Python callable, wrapping unexpected
|
|
322
|
+
exceptions as SemanticError. Mirrors expand_call_macro's pattern.
|
|
323
|
+
"""
|
|
324
|
+
from .diagnostics import SemanticError
|
|
325
|
+
from .macro_api import MacroError, ast as _ast_builder
|
|
326
|
+
_ast_builder.reset_tmp_counter()
|
|
327
|
+
try:
|
|
328
|
+
return fn(*args, **kwargs)
|
|
329
|
+
except MacroError as e:
|
|
330
|
+
raise SemanticError(str(e), e.loc or loc) from e
|
|
331
|
+
except SemanticError:
|
|
332
|
+
raise
|
|
333
|
+
except Exception as e:
|
|
334
|
+
raise SemanticError(
|
|
335
|
+
f"{what}: macro raised {type(e).__name__}: {e}", loc) from e
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def validate_builder_macro(
|
|
339
|
+
macro_cls: type, ctx_obj: Any, args: Any, qname: str, loc: Any,
|
|
340
|
+
) -> Any:
|
|
341
|
+
"""Instantiate a @builder_macro state class.
|
|
342
|
+
|
|
343
|
+
``macro_cls`` is the user-defined class. ``ctx_obj`` is a
|
|
344
|
+
``BuilderContext`` (passed positionally to ``__init__``). ``args`` is
|
|
345
|
+
a ``MacroArgs`` value carrying the constructor's positional + kw
|
|
346
|
+
arguments. Returns the constructed state instance.
|
|
347
|
+
"""
|
|
348
|
+
return _wrap_macro_call(
|
|
349
|
+
macro_cls, qname, loc, (ctx_obj, args), {})
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def expand_builder_method(
|
|
353
|
+
handler: Callable, qname: str, ctx_obj: Any, args: Any, loc: Any,
|
|
354
|
+
) -> Any:
|
|
355
|
+
"""Invoke a @builder_method / @builder_returns / @builder_terminal
|
|
356
|
+
handler bound to its state instance. Returns the handler's return
|
|
357
|
+
value (None for void steps; child instance for builder_returns;
|
|
358
|
+
TypeInfo for builder_terminal).
|
|
359
|
+
"""
|
|
360
|
+
return _wrap_macro_call(
|
|
361
|
+
handler, qname, loc, (ctx_obj, args), {})
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class MacroRegistry:
|
|
365
|
+
"""Registry of loaded class macros.
|
|
366
|
+
|
|
367
|
+
Maps ``(module_name, decorator_name)`` to the Python callable that
|
|
368
|
+
implements the macro.
|
|
369
|
+
"""
|
|
370
|
+
|
|
371
|
+
def __init__(self, search_dirs: list[Path] | None = None) -> None:
|
|
372
|
+
self._macros: dict[tuple[str, str], Callable] = {}
|
|
373
|
+
self._call_macros: dict[tuple[str, str], Callable] = {}
|
|
374
|
+
# Builder-trace macros: (module, name) -> class object
|
|
375
|
+
self._builder_macros: dict[tuple[str, str], type] = {}
|
|
376
|
+
self._modules: dict[str, Any] = {}
|
|
377
|
+
self._loaded_modules: set[str] = set()
|
|
378
|
+
# module_name -> {dep_module: names_or_None}
|
|
379
|
+
# None means all exports, list means specific names only.
|
|
380
|
+
self._macro_deps: dict[str, dict[str, list[str] | None]] = {}
|
|
381
|
+
# Lib search dirs for resolving macro-to-macro imports
|
|
382
|
+
self._search_dirs: list[Path] = list(search_dirs or [])
|
|
383
|
+
# Guard against circular macro imports
|
|
384
|
+
self._loading: set[str] = set()
|
|
385
|
+
|
|
386
|
+
def register(self, module: str, name: str, func: Callable) -> None:
|
|
387
|
+
self._macros[(module, name)] = func
|
|
388
|
+
|
|
389
|
+
def get_macro(self, module: str, name: str) -> Callable | None:
|
|
390
|
+
return self._macros.get((module, name))
|
|
391
|
+
|
|
392
|
+
def get_call_macro(self, module: str, name: str) -> Callable | None:
|
|
393
|
+
return self._call_macros.get((module, name))
|
|
394
|
+
|
|
395
|
+
def get_builder_macro(self, module: str, name: str) -> type | None:
|
|
396
|
+
"""Look up a @builder_macro state class by (module, name)."""
|
|
397
|
+
return self._builder_macros.get((module, name))
|
|
398
|
+
|
|
399
|
+
def builder_macro_modules(self) -> set[str]:
|
|
400
|
+
"""Module names that have any registered @builder_macro classes."""
|
|
401
|
+
return {mod for mod, _ in self._builder_macros}
|
|
402
|
+
|
|
403
|
+
def has_builder_macros(self) -> bool:
|
|
404
|
+
"""True if any @builder_macro classes are registered."""
|
|
405
|
+
return bool(self._builder_macros)
|
|
406
|
+
|
|
407
|
+
def get_export(self, module: str, name: str) -> Any | None:
|
|
408
|
+
"""Look up any exported name from a loaded macro module."""
|
|
409
|
+
mod = self._modules.get(module)
|
|
410
|
+
if mod is None:
|
|
411
|
+
return None
|
|
412
|
+
return getattr(mod, name, None)
|
|
413
|
+
|
|
414
|
+
def get_deps(self, module_name: str) -> dict[str, list[str] | None]:
|
|
415
|
+
"""Return MACRO_DEPS for a loaded macro module.
|
|
416
|
+
|
|
417
|
+
Returns dict mapping dep module name to list of specific names (or None
|
|
418
|
+
for all exports). Empty dict if no deps declared.
|
|
419
|
+
"""
|
|
420
|
+
return self._macro_deps.get(module_name, {})
|
|
421
|
+
|
|
422
|
+
def _resolve_macro_import(self, name: str) -> Any | None:
|
|
423
|
+
"""Resolve an import to another macro module from lib search paths.
|
|
424
|
+
|
|
425
|
+
Returns the loaded module object, or None if not found.
|
|
426
|
+
"""
|
|
427
|
+
if name in self._modules:
|
|
428
|
+
return self._modules[name]
|
|
429
|
+
if name in self._loading:
|
|
430
|
+
raise ImportError(f"Circular macro module import: '{name}'")
|
|
431
|
+
for d in self._search_dirs:
|
|
432
|
+
path = d / Path(name.replace(".", "/")).with_suffix(".py")
|
|
433
|
+
if path.is_file():
|
|
434
|
+
source = path.read_text()
|
|
435
|
+
if is_macro_module_source(source):
|
|
436
|
+
self.load_module(name, path)
|
|
437
|
+
return self._modules.get(name)
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
def is_loaded(self, module_name: str) -> bool:
|
|
441
|
+
return module_name in self._loaded_modules
|
|
442
|
+
|
|
443
|
+
def load_module(self, module_name: str, file_path: Path) -> None:
|
|
444
|
+
"""Load a macro module via CPython and register its exports.
|
|
445
|
+
|
|
446
|
+
Functions decorated with ``@class_macro`` are registered automatically.
|
|
447
|
+
"""
|
|
448
|
+
if module_name in self._loaded_modules:
|
|
449
|
+
return
|
|
450
|
+
|
|
451
|
+
# Ensure tpyc is importable (macro modules import from tpyc.macro_api)
|
|
452
|
+
tpyc_parent = str(Path(__file__).resolve().parent.parent)
|
|
453
|
+
if tpyc_parent not in sys.path:
|
|
454
|
+
sys.path.insert(0, tpyc_parent)
|
|
455
|
+
|
|
456
|
+
spec = importlib.util.spec_from_file_location(
|
|
457
|
+
f"_tpy_macro_{module_name}", str(file_path)
|
|
458
|
+
)
|
|
459
|
+
if spec is None or spec.loader is None:
|
|
460
|
+
raise RuntimeError(
|
|
461
|
+
f"Cannot load macro module '{module_name}' from {file_path}"
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
mod = importlib.util.module_from_spec(spec)
|
|
465
|
+
mod.__builtins__ = _make_restricted_builtins(module_name, self)
|
|
466
|
+
self._loading.add(module_name)
|
|
467
|
+
try:
|
|
468
|
+
spec.loader.exec_module(mod)
|
|
469
|
+
except Exception as e:
|
|
470
|
+
_macro_api._pending_macro_deps = None
|
|
471
|
+
raise RuntimeError(
|
|
472
|
+
f"Error executing macro module '{module_name}' ({file_path}): {e}"
|
|
473
|
+
) from e
|
|
474
|
+
finally:
|
|
475
|
+
self._loading.discard(module_name)
|
|
476
|
+
|
|
477
|
+
self._modules[module_name] = mod
|
|
478
|
+
|
|
479
|
+
# Read deps registered via macro_deps() during module execution
|
|
480
|
+
if _macro_api._pending_macro_deps is not None:
|
|
481
|
+
self._macro_deps[module_name] = _macro_api._pending_macro_deps
|
|
482
|
+
_macro_api._pending_macro_deps = None
|
|
483
|
+
|
|
484
|
+
# Scan for @class_macro and @call_macro decorated functions, and
|
|
485
|
+
# @builder_macro decorated classes.
|
|
486
|
+
for attr_name in dir(mod):
|
|
487
|
+
obj = getattr(mod, attr_name)
|
|
488
|
+
if isinstance(obj, type) and getattr(obj, '_is_builder_macro', False):
|
|
489
|
+
self._builder_macros[(module_name, attr_name)] = obj
|
|
490
|
+
continue
|
|
491
|
+
if callable(obj):
|
|
492
|
+
if getattr(obj, '_is_class_macro', False):
|
|
493
|
+
self.register(module_name, attr_name, obj)
|
|
494
|
+
if getattr(obj, '_is_call_macro', False):
|
|
495
|
+
self._call_macros[(module_name, attr_name)] = obj
|
|
496
|
+
|
|
497
|
+
self._loaded_modules.add(module_name)
|
tpyc/module_names.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Module-name normalization helpers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .typesys import TypeRegistry
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def module_from_qname(qname: str, registry: TypeRegistry) -> str | None:
|
|
11
|
+
"""Return the module whose generated header declares the named
|
|
12
|
+
symbol, used to drive `#include` emission and cross-module lookups.
|
|
13
|
+
|
|
14
|
+
A `@builtin_type` record's qname is a TPy-side label that need not
|
|
15
|
+
match its defining file: `Poll` is tagged `tpy.coro.Poll` but
|
|
16
|
+
declared in `tpy/_core/_types.py`. Prefix-walking the qname to
|
|
17
|
+
`tpy.coro` would route includes through the wrong header. For
|
|
18
|
+
records, consult the registry's qname indexes directly and return
|
|
19
|
+
`RecordInfo.module`. The two indexes (`_qname_index` for builtins,
|
|
20
|
+
`_user_qname_index` for user records) are accessed in preference to
|
|
21
|
+
the public `find_record_by_qname` because its short-name fallback
|
|
22
|
+
walks every module's records dict (O(workspace size)), wrong for a
|
|
23
|
+
helper that runs on every nominal type during reach analysis.
|
|
24
|
+
|
|
25
|
+
Falls back to a prefix walk for enums, protocols, parser
|
|
26
|
+
placeholders, and any other qname not in the record indexes.
|
|
27
|
+
"""
|
|
28
|
+
record = registry._qname_index.get(qname) or registry._user_qname_index.get(qname)
|
|
29
|
+
if record is not None and record.module:
|
|
30
|
+
return record.module
|
|
31
|
+
parts = qname.split(".")
|
|
32
|
+
for i in range(len(parts) - 1, 0, -1):
|
|
33
|
+
candidate = ".".join(parts[:i])
|
|
34
|
+
if registry.get_module(candidate) is not None:
|
|
35
|
+
return candidate
|
|
36
|
+
if len(parts) >= 2:
|
|
37
|
+
return parts[0]
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def public_module_name(module_name: str, cpp_namespace: str | None = None) -> str:
|
|
42
|
+
"""Map a private submodule name to its public module identity.
|
|
43
|
+
|
|
44
|
+
e.g. "tpy._core._types" -> "tpy", "tpy._builtins._list" -> "tpy"
|
|
45
|
+
|
|
46
|
+
When cpp_namespace is provided (e.g. "tpystd::typing" for tpy._typing),
|
|
47
|
+
derives the public name from the namespace instead of the module path.
|
|
48
|
+
This handles cross-package implementations like typing protocols defined
|
|
49
|
+
in tpy._typing.
|
|
50
|
+
"""
|
|
51
|
+
if cpp_namespace and "._" in module_name:
|
|
52
|
+
# Derive from namespace: "tpystd::typing" -> "typing", "tpystd::tpy" -> "tpy"
|
|
53
|
+
ns_parts = cpp_namespace.split("::")
|
|
54
|
+
# Skip the common prefix (e.g. "tpystd") and join the rest
|
|
55
|
+
if len(ns_parts) >= 2 and ns_parts[0] == "tpystd":
|
|
56
|
+
return ".".join(ns_parts[1:])
|
|
57
|
+
parts = module_name.split(".")
|
|
58
|
+
# Keep only parts up to (but not including) the first private component
|
|
59
|
+
public_parts = []
|
|
60
|
+
for part in parts:
|
|
61
|
+
if part.startswith("_"):
|
|
62
|
+
break
|
|
63
|
+
public_parts.append(part)
|
|
64
|
+
return ".".join(public_parts) if public_parts else module_name
|
tpyc/modules/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython built-in modules infrastructure.
|
|
3
|
+
|
|
4
|
+
Provides a registry for built-in functions and types that can be used
|
|
5
|
+
by the semantic analyzer and code generator.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# --- Data classes, constants ---
|
|
9
|
+
from tpyc.modules.defs import ( # noqa: F401
|
|
10
|
+
ParamDef, MethodDef,
|
|
11
|
+
DUNDER_CPP_TEMPLATES, get_dunder_cpp_template,
|
|
12
|
+
BINOP_TO_METHOD, BINOP_TO_RMETHOD, AUGOP_TO_IMETHOD, UNARYOP_TO_METHOD,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# --- Module registry ---
|
|
16
|
+
from tpyc.modules.registry import ( # noqa: F401
|
|
17
|
+
get_builtin_module_names, get_builtin_type_obj,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# --- Method resolution, iteration helpers ---
|
|
21
|
+
# (Generic type factories and lookups live in `tpyc.type_def_registry`;
|
|
22
|
+
# import from there directly.)
|
|
23
|
+
from tpyc.modules.type_resolution import ( # noqa: F401
|
|
24
|
+
_resolve_concrete_type_name, _resolve_extends_type_arg,
|
|
25
|
+
extract_type_params, resolve_method,
|
|
26
|
+
ITERABLE_PROTOCOL_QNAMES,
|
|
27
|
+
is_native_iterable, get_extends_protocol_type_arg,
|
|
28
|
+
get_error_return_next_element_type,
|
|
29
|
+
get_iter_element_type, get_iterable_element_type,
|
|
30
|
+
get_span_element_type, get_span_return_type,
|
|
31
|
+
)
|
tpyc/modules/defs.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Built-in module data classes and constant tables.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from tpyc.typesys import TpyType
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ParamDef:
|
|
16
|
+
"""Parameter definition for a function/method."""
|
|
17
|
+
name: str
|
|
18
|
+
type: "TpyType" # TpyType, use TypeParamRef("T") for type params
|
|
19
|
+
requires_mutable_lvalue: bool = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class MethodDef:
|
|
24
|
+
"""Definition of a function overload or type method."""
|
|
25
|
+
params: list[ParamDef]
|
|
26
|
+
returns: "TpyType" # TpyType, use TypeParamRef("T") for type params
|
|
27
|
+
cpp: str # Template: "{0}" for args, "{self}" for receiver
|
|
28
|
+
is_noalloc: bool = False
|
|
29
|
+
is_readonly: bool = False
|
|
30
|
+
is_pure: bool = False
|
|
31
|
+
is_static: bool = False
|
|
32
|
+
# Per-method type params and bounds (for constraining class-level type params)
|
|
33
|
+
type_params: list[str] = field(default_factory=list)
|
|
34
|
+
type_param_bounds: dict[str, "TpyType"] = field(default_factory=dict)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# C++ expression templates for Python dunder methods.
|
|
38
|
+
# Used when .py-defined protocols don't carry cpp templates.
|
|
39
|
+
DUNDER_CPP_TEMPLATES: dict[str, str] = {
|
|
40
|
+
"__len__": "::tpy::__len__({self})",
|
|
41
|
+
"__getitem__": "::tpy::__getitem__({self}, {0})",
|
|
42
|
+
"__setitem__": "::tpy::__setitem__({self}, {0}, {1})",
|
|
43
|
+
"__iter__": "::tpy::__iter__({self})",
|
|
44
|
+
"__next__": "{self}.__next__()",
|
|
45
|
+
"__contains__": "::tpy::__contains__({self}, {0})",
|
|
46
|
+
"__delitem__": "::tpy::__delitem__({self}, {0})",
|
|
47
|
+
"__bool__": "::tpy::__bool__({self})",
|
|
48
|
+
"__str__": "::tpy::__str__({self})",
|
|
49
|
+
"__repr__": "::tpy::repr_of({self})",
|
|
50
|
+
"__hash__": "::tpy::__hash__({self})",
|
|
51
|
+
"__deref__": "::tpy::deref_check({self})",
|
|
52
|
+
"__span__": "::tpy::as_span({self})",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_dunder_cpp_template(method_name: str) -> str | None:
|
|
57
|
+
"""Get the C++ expression template for a dunder method, or None."""
|
|
58
|
+
return DUNDER_CPP_TEMPLATES.get(method_name)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Operator to method name mappings
|
|
62
|
+
BINOP_TO_METHOD = {
|
|
63
|
+
"+": "__add__", "-": "__sub__", "*": "__mul__",
|
|
64
|
+
"div": "__truediv__", "//": "__floordiv__", "%": "__mod__", "**": "__pow__",
|
|
65
|
+
"<<": "__lshift__", ">>": "__rshift__",
|
|
66
|
+
"&": "__and__", "|": "__or__", "^": "__xor__",
|
|
67
|
+
"==": "__eq__", "!=": "__ne__",
|
|
68
|
+
"<": "__lt__", "<=": "__le__", ">": "__gt__", ">=": "__ge__",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
BINOP_TO_RMETHOD = {
|
|
72
|
+
"+": "__radd__", "-": "__rsub__", "*": "__rmul__",
|
|
73
|
+
"div": "__rtruediv__", "//": "__rfloordiv__", "%": "__rmod__", "**": "__rpow__",
|
|
74
|
+
"<<": "__rlshift__", ">>": "__rrshift__",
|
|
75
|
+
"&": "__rand__", "|": "__ror__", "^": "__rxor__",
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
AUGOP_TO_IMETHOD = {
|
|
79
|
+
"+": "__iadd__", "-": "__isub__", "*": "__imul__",
|
|
80
|
+
"div": "__itruediv__", "//": "__ifloordiv__", "%": "__imod__",
|
|
81
|
+
"<<": "__ilshift__", ">>": "__irshift__",
|
|
82
|
+
"|": "__ior__", "&": "__iand__", "^": "__ixor__",
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
UNARYOP_TO_METHOD = {
|
|
86
|
+
"+": "__pos__",
|
|
87
|
+
"-": "__neg__",
|
|
88
|
+
"~": "__invert__",
|
|
89
|
+
}
|