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,684 @@
|
|
|
1
|
+
"""Builder-trace macro expansion sub-pass.
|
|
2
|
+
|
|
3
|
+
Function-body and record-method-body expansion runs in pass 5.5
|
|
4
|
+
(``SemanticAnalyzer._expand_builder_traces``), after class-constants
|
|
5
|
+
analysis (pass 5) and before record-method-body analysis (pass 6), so
|
|
6
|
+
synthesized records / functions are first-class participants in passes
|
|
7
|
+
6 and 7. Top-level expansion runs inside ``_analyze_top_level`` (pass
|
|
8
|
+
4 is itself the body-analysis pass for module-level code, so expansion
|
|
9
|
+
has to run there). Detects @builder_macro constructor calls, walks the
|
|
10
|
+
body linearly, dispatches builder methods to user handlers, and splices
|
|
11
|
+
synthesized declarations + a rewritten call site back into the body.
|
|
12
|
+
See docs/MACRO_DESIGN.md (Phase 7) for the design.
|
|
13
|
+
|
|
14
|
+
Phase A (current): the happy path -- ctor, methods, terminal -- without
|
|
15
|
+
the full v1 hard-error rules around tracked-symbol misuse, conditionals,
|
|
16
|
+
loops, or multiple terminals. Those land in phase B.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
22
|
+
|
|
23
|
+
from ..parse.nodes import (
|
|
24
|
+
TpyAssign, TpyCall, TpyMethodCall, TpyExprStmt, TpyVarDecl,
|
|
25
|
+
TpyName, TpyStmt, TpyExpr, TpyFunction, TpyRecord, TpyLambda,
|
|
26
|
+
TpyNestedDef,
|
|
27
|
+
TpyStrLiteral, TpyIntLiteral, TpyFloatLiteral, TpyBoolLiteral,
|
|
28
|
+
TpyNoneLiteral, TpyUnaryOp,
|
|
29
|
+
)
|
|
30
|
+
from ..typesys import (
|
|
31
|
+
FieldInfo, NominalType, OwnType, TpyType, VOID, STR, STRVIEW, BOOL, BIGINT,
|
|
32
|
+
FLOAT, FLOAT32,
|
|
33
|
+
INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64,
|
|
34
|
+
make_list,
|
|
35
|
+
)
|
|
36
|
+
from ..diagnostics import SemanticError
|
|
37
|
+
from ..symbol_binding import SymbolKind, is_kind, walk_attribute_chain
|
|
38
|
+
from ..macro_api import (
|
|
39
|
+
MacroArg, MacroArgs, BuilderContext, TypeInfo, MacroError,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from .context import SemanticContext
|
|
44
|
+
from .registration import TypeRegistrar
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Synthesized records and functions get a private prefix so they aren't
|
|
48
|
+
# treated as user-exported names. Matches the compiler-internal naming
|
|
49
|
+
# convention used elsewhere (e.g. __tpy_init, __tpy_main).
|
|
50
|
+
_SYNTH_PREFIX = "__tpy_builder_"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Kind tags for handlers discovered on a @builder_macro class.
|
|
54
|
+
_KIND_METHOD = "method"
|
|
55
|
+
_KIND_RETURNS = "returns"
|
|
56
|
+
_KIND_TERMINAL = "terminal"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class _HandlerSpec:
|
|
61
|
+
fn: Callable
|
|
62
|
+
kind: str
|
|
63
|
+
child_class: type | None = None # only for kind == _KIND_RETURNS
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass
|
|
67
|
+
class _TrackedSymbol:
|
|
68
|
+
"""A live tracked symbol bound by a @builder_macro ctor or sub-builder."""
|
|
69
|
+
var_name: str
|
|
70
|
+
state: object
|
|
71
|
+
macro_qname: str
|
|
72
|
+
handlers: dict[str, _HandlerSpec]
|
|
73
|
+
# var_name of the @builder_returns parent that spawned this symbol,
|
|
74
|
+
# or None for top-level (ctor-bound) symbols. Used to cascade
|
|
75
|
+
# close-on-terminal: when the root @builder_terminal fires, every
|
|
76
|
+
# descendant sub-builder is closed too. Sub-builders don't have
|
|
77
|
+
# their own terminal -- they contribute to the root's terminal.
|
|
78
|
+
parent_var: str | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class _PendingReplacement:
|
|
83
|
+
fn_name: str
|
|
84
|
+
args: MacroArgs
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _scan_handlers(macro_cls: type) -> dict[str, _HandlerSpec]:
|
|
88
|
+
"""Collect @builder_method / @builder_returns / @builder_terminal
|
|
89
|
+
handlers declared on a builder class.
|
|
90
|
+
"""
|
|
91
|
+
out: dict[str, _HandlerSpec] = {}
|
|
92
|
+
for attr in dir(macro_cls):
|
|
93
|
+
if attr.startswith("__") and attr.endswith("__"):
|
|
94
|
+
continue
|
|
95
|
+
fn = getattr(macro_cls, attr, None)
|
|
96
|
+
if not callable(fn):
|
|
97
|
+
continue
|
|
98
|
+
if getattr(fn, "_is_builder_terminal", False):
|
|
99
|
+
out[attr] = _HandlerSpec(fn, _KIND_TERMINAL)
|
|
100
|
+
elif getattr(fn, "_is_builder_returns", False):
|
|
101
|
+
child = getattr(fn, "_builder_child_class", None)
|
|
102
|
+
out[attr] = _HandlerSpec(fn, _KIND_RETURNS, child_class=child)
|
|
103
|
+
elif getattr(fn, "_is_builder_method", False):
|
|
104
|
+
out[attr] = _HandlerSpec(fn, _KIND_METHOD)
|
|
105
|
+
return out
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _macro_arg_from_expr(expr: TpyExpr) -> MacroArg:
|
|
109
|
+
"""Wrap an expression as a MacroArg with a best-effort literal type.
|
|
110
|
+
|
|
111
|
+
Builder-trace runs before body analysis, so resolved types aren't
|
|
112
|
+
on expressions yet. We synthesize a minimal TypeInfo from the literal
|
|
113
|
+
kind when possible. Macros generally only need MacroArg.expr (for
|
|
114
|
+
literal evaluation); the type field is provided so kwarg_macroarg
|
|
115
|
+
callers see something sensible for the common cases.
|
|
116
|
+
"""
|
|
117
|
+
return MacroArg(expr=expr, type=_typeinfo_from_literal(expr))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# Bare-name builtins recognized as ``type=`` references in builder
|
|
121
|
+
# macros. Mapping these to their real TpyType lets macros use
|
|
122
|
+
# TypeInfo's category helpers (``is_int``, ``is_bigint``, ``is_float``,
|
|
123
|
+
# ...) instead of name-string comparisons. User-defined types still
|
|
124
|
+
# fall through to a placeholder until full type-name resolution lands
|
|
125
|
+
# in builder-trace.
|
|
126
|
+
_BUILTIN_TYPE_NAMES: dict[str, TpyType] = {
|
|
127
|
+
"str": STR, "int": BIGINT, "float": FLOAT, "bool": BOOL,
|
|
128
|
+
"Int8": INT8, "Int16": INT16, "Int32": INT32, "Int64": INT64,
|
|
129
|
+
"UInt8": UINT8, "UInt16": UINT16, "UInt32": UINT32, "UInt64": UINT64,
|
|
130
|
+
"Float32": FLOAT32,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _typeinfo_from_literal(expr: TpyExpr) -> TypeInfo:
|
|
135
|
+
if isinstance(expr, TpyBoolLiteral):
|
|
136
|
+
return TypeInfo.from_tpy_type(BOOL)
|
|
137
|
+
if isinstance(expr, TpyIntLiteral):
|
|
138
|
+
return TypeInfo.from_tpy_type(BIGINT)
|
|
139
|
+
if isinstance(expr, TpyFloatLiteral):
|
|
140
|
+
return TypeInfo.from_tpy_type(FLOAT)
|
|
141
|
+
if isinstance(expr, TpyStrLiteral):
|
|
142
|
+
return TypeInfo.from_tpy_type(STRVIEW)
|
|
143
|
+
if isinstance(expr, TpyNoneLiteral):
|
|
144
|
+
return TypeInfo("None", _tpy_type=None)
|
|
145
|
+
if isinstance(expr, TpyName):
|
|
146
|
+
builtin = _BUILTIN_TYPE_NAMES.get(expr.name)
|
|
147
|
+
if builtin is not None:
|
|
148
|
+
return TypeInfo.from_tpy_type(builtin)
|
|
149
|
+
# User-defined types stay as placeholders until full type-name
|
|
150
|
+
# resolution lands in builder-trace.
|
|
151
|
+
return TypeInfo(expr.name, _tpy_type=None)
|
|
152
|
+
return TypeInfo("?", _tpy_type=None)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _build_macro_args(args: list[TpyExpr], kwargs: dict[str, TpyExpr]) -> MacroArgs:
|
|
156
|
+
return MacroArgs(
|
|
157
|
+
positional=[_macro_arg_from_expr(a) for a in args],
|
|
158
|
+
kwargs={k: _macro_arg_from_expr(v) for k, v in kwargs.items()},
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _extract_binding(stmt: TpyStmt) -> tuple[str | None, TpyExpr | None]:
|
|
163
|
+
"""If ``stmt`` binds a single name to an RHS expression, return
|
|
164
|
+
``(name, rhs)``. Otherwise return ``(None, None)``.
|
|
165
|
+
|
|
166
|
+
Handles both first-time declarations (``TpyVarDecl``) and reassignments
|
|
167
|
+
(``TpyAssign`` with a ``TpyName`` target).
|
|
168
|
+
"""
|
|
169
|
+
if isinstance(stmt, TpyVarDecl):
|
|
170
|
+
return stmt.name, stmt.init
|
|
171
|
+
if isinstance(stmt, TpyAssign) and isinstance(stmt.target, TpyName):
|
|
172
|
+
return stmt.target.name, stmt.value
|
|
173
|
+
return None, None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class BuilderTraceExpander:
|
|
177
|
+
"""Expand a function body containing @builder_macro constructor calls.
|
|
178
|
+
|
|
179
|
+
Construct one expander per body. Call ``expand(body)`` to get a
|
|
180
|
+
rewritten body. The expander mutates ``ctx.registry`` and ``module``
|
|
181
|
+
directly via the registrar to register synthesized declarations.
|
|
182
|
+
|
|
183
|
+
No-op when the body contains no builder constructors.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
def __init__(
|
|
187
|
+
self,
|
|
188
|
+
ctx: 'SemanticContext',
|
|
189
|
+
registrar: 'TypeRegistrar',
|
|
190
|
+
module: Any, # TpyModule -- imported lazily to avoid cycle
|
|
191
|
+
function_being_traced: str,
|
|
192
|
+
) -> None:
|
|
193
|
+
self.ctx = ctx
|
|
194
|
+
self.registrar = registrar
|
|
195
|
+
self.module = module
|
|
196
|
+
self.function_being_traced = function_being_traced
|
|
197
|
+
self._tracked: dict[str, _TrackedSymbol] = {}
|
|
198
|
+
self._pending_replacement: _PendingReplacement | None = None
|
|
199
|
+
# Trace-rule bookkeeping (Phase B).
|
|
200
|
+
self._all_tracked_names: set[str] = set()
|
|
201
|
+
self._open_traces: dict[str, Any] = {} # name -> ctor loc
|
|
202
|
+
|
|
203
|
+
# ------------------------------------------------------------------
|
|
204
|
+
# Body walk
|
|
205
|
+
# ------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
def expand(self, body: list[TpyStmt] | None) -> list[TpyStmt] | None:
|
|
208
|
+
if body is None:
|
|
209
|
+
return body
|
|
210
|
+
macro_reg = self.ctx.macro_registry
|
|
211
|
+
if macro_reg is None or not macro_reg.has_builder_macros():
|
|
212
|
+
return body
|
|
213
|
+
new_body: list[TpyStmt] = []
|
|
214
|
+
for stmt in body:
|
|
215
|
+
replacement = self._process_stmt(stmt)
|
|
216
|
+
if replacement is _DROP:
|
|
217
|
+
continue
|
|
218
|
+
if replacement is None:
|
|
219
|
+
new_body.append(stmt)
|
|
220
|
+
else:
|
|
221
|
+
new_body.append(replacement)
|
|
222
|
+
# Trace-rule validation (Phase B). Order matters: leaks fire
|
|
223
|
+
# before "trace never closed" so that a symbol used illegally
|
|
224
|
+
# gets the more specific error rather than a generic missing-
|
|
225
|
+
# terminal one.
|
|
226
|
+
if self._all_tracked_names:
|
|
227
|
+
self._validate_no_tracked_leaks(new_body)
|
|
228
|
+
self._check_no_open_traces()
|
|
229
|
+
return new_body
|
|
230
|
+
|
|
231
|
+
def _reject_active_reassignment(self, name: str, loc: Any) -> None:
|
|
232
|
+
"""Raise if ``name`` is currently bound as an active tracked
|
|
233
|
+
builder symbol. Shared between ctor binding, ``@builder_returns``
|
|
234
|
+
rebinding, and the post-dispatch fall-through reassignment check.
|
|
235
|
+
Closed names are not rejected -- the trace has finished, the
|
|
236
|
+
name is free to take on any other meaning.
|
|
237
|
+
"""
|
|
238
|
+
if name in self._tracked:
|
|
239
|
+
raise SemanticError(
|
|
240
|
+
f"builder-trace symbol '{name}' cannot be reassigned",
|
|
241
|
+
loc,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
def _check_no_open_traces(self) -> None:
|
|
245
|
+
if not self._open_traces:
|
|
246
|
+
return
|
|
247
|
+
name, loc = next(iter(self._open_traces.items()))
|
|
248
|
+
raise SemanticError(
|
|
249
|
+
f"builder-trace symbol '{name}' was never closed by a "
|
|
250
|
+
f"@builder_terminal call before the end of "
|
|
251
|
+
f"'{self.function_being_traced}'",
|
|
252
|
+
loc,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def _validate_no_tracked_leaks(self, body: list[TpyStmt]) -> None:
|
|
256
|
+
tracked = self._all_tracked_names
|
|
257
|
+
for stmt in body:
|
|
258
|
+
self._validate_stmt(stmt, tracked, in_control_flow=False)
|
|
259
|
+
|
|
260
|
+
def _validate_stmt(
|
|
261
|
+
self, stmt: TpyStmt, tracked: set[str], *, in_control_flow: bool,
|
|
262
|
+
) -> None:
|
|
263
|
+
for expr in stmt.exprs():
|
|
264
|
+
if expr is not None:
|
|
265
|
+
self._validate_expr(expr, tracked, stmt,
|
|
266
|
+
in_control_flow=in_control_flow)
|
|
267
|
+
for nested in stmt.sub_bodies():
|
|
268
|
+
for inner in nested:
|
|
269
|
+
self._validate_stmt(inner, tracked, in_control_flow=True)
|
|
270
|
+
# TpyNestedDef.sub_bodies() returns []; recurse into its
|
|
271
|
+
# function body explicitly so a tracked symbol captured by a
|
|
272
|
+
# nested def is flagged.
|
|
273
|
+
if isinstance(stmt, TpyNestedDef):
|
|
274
|
+
for inner in stmt.func.body:
|
|
275
|
+
self._validate_stmt(inner, tracked, in_control_flow=True)
|
|
276
|
+
|
|
277
|
+
def _validate_expr(
|
|
278
|
+
self, expr: TpyExpr, tracked: set[str], stmt: TpyStmt,
|
|
279
|
+
*, in_control_flow: bool,
|
|
280
|
+
) -> None:
|
|
281
|
+
if isinstance(expr, TpyName) and expr.name in tracked:
|
|
282
|
+
loc = getattr(expr, "loc", None) or getattr(stmt, "loc", None)
|
|
283
|
+
if in_control_flow:
|
|
284
|
+
raise SemanticError(
|
|
285
|
+
f"builder-trace symbol '{expr.name}' may not be used "
|
|
286
|
+
f"inside a control-flow block, lambda, or nested def",
|
|
287
|
+
loc,
|
|
288
|
+
)
|
|
289
|
+
raise SemanticError(
|
|
290
|
+
f"builder-trace symbol '{expr.name}' may only appear as "
|
|
291
|
+
f"the receiver of a registered @builder_method call",
|
|
292
|
+
loc,
|
|
293
|
+
)
|
|
294
|
+
# TpyLambda.children() returns [] to keep generic walks out of
|
|
295
|
+
# closure bodies; recurse explicitly so a tracked symbol
|
|
296
|
+
# captured by a lambda is flagged. The lambda body is itself
|
|
297
|
+
# an expression.
|
|
298
|
+
if isinstance(expr, TpyLambda):
|
|
299
|
+
self._validate_expr(expr.body, tracked, stmt,
|
|
300
|
+
in_control_flow=True)
|
|
301
|
+
return
|
|
302
|
+
for child in expr.children():
|
|
303
|
+
self._validate_expr(child, tracked, stmt,
|
|
304
|
+
in_control_flow=in_control_flow)
|
|
305
|
+
|
|
306
|
+
def _process_stmt(self, stmt: TpyStmt) -> Any:
|
|
307
|
+
# x = BuilderClass(...) -- start a new trace.
|
|
308
|
+
# Both TpyAssign (rebinding) and TpyVarDecl (first declaration)
|
|
309
|
+
# can carry the binding RHS, and the ctor itself can appear
|
|
310
|
+
# either as a bare-name call (``ArgumentParser()`` after
|
|
311
|
+
# ``from argparse import ArgumentParser``) or as a qualified
|
|
312
|
+
# method call (``argparse.ArgumentParser()`` after
|
|
313
|
+
# ``import argparse``). Both forms carry resolved_import.
|
|
314
|
+
target_name, rhs = _extract_binding(stmt)
|
|
315
|
+
if target_name is not None and rhs is not None:
|
|
316
|
+
if isinstance(rhs, (TpyCall, TpyMethodCall)):
|
|
317
|
+
builder_cls = self._lookup_builder_macro(rhs)
|
|
318
|
+
if builder_cls is not None:
|
|
319
|
+
self._handle_ctor(target_name, rhs, builder_cls)
|
|
320
|
+
return _DROP
|
|
321
|
+
if isinstance(rhs, TpyMethodCall):
|
|
322
|
+
rep = self._handle_method_call(stmt, rhs, lhs=target_name)
|
|
323
|
+
if rep is not _NOT_HANDLED:
|
|
324
|
+
return rep
|
|
325
|
+
# Reassignment to an actively tracked builder symbol --
|
|
326
|
+
# forbidden because the leak validator wouldn't catch this on
|
|
327
|
+
# its own (the RHS may not reference the tracked name). Once
|
|
328
|
+
# the trace has been closed by a terminal, the name is fair
|
|
329
|
+
# game for any rebinding.
|
|
330
|
+
self._reject_active_reassignment(target_name, getattr(stmt, "loc", None))
|
|
331
|
+
# bare method call: parser.method(...)
|
|
332
|
+
if isinstance(stmt, TpyExprStmt) and isinstance(stmt.expr, TpyMethodCall):
|
|
333
|
+
rep = self._handle_method_call(stmt, stmt.expr, lhs=None)
|
|
334
|
+
if rep is not _NOT_HANDLED:
|
|
335
|
+
return rep
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
# ------------------------------------------------------------------
|
|
339
|
+
# Constructor handling
|
|
340
|
+
# ------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
def _lookup_builder_macro(self, call: TpyCall | TpyMethodCall) -> type | None:
|
|
343
|
+
"""Return the @builder_macro state class targeted by this call,
|
|
344
|
+
or None. Works for both ``Builder()`` (TpyCall after
|
|
345
|
+
``from mod import Builder``) and ``mod.Builder()`` (TpyMethodCall
|
|
346
|
+
after ``import mod``); both carry ``resolved_import`` (immediate
|
|
347
|
+
import source). The chain walk recovers the registry's canonical
|
|
348
|
+
(ultimate_module, name) key for re-exports through plain modules.
|
|
349
|
+
"""
|
|
350
|
+
macro_reg = self.ctx.macro_registry
|
|
351
|
+
if macro_reg is None or call.resolved_import is None:
|
|
352
|
+
return None
|
|
353
|
+
mod_name, obj_name = call.resolved_import
|
|
354
|
+
macro_cls = macro_reg.get_builder_macro(mod_name, obj_name)
|
|
355
|
+
if macro_cls is not None:
|
|
356
|
+
return macro_cls
|
|
357
|
+
result = walk_attribute_chain(
|
|
358
|
+
self.ctx.registry, mod_name, obj_name,
|
|
359
|
+
is_kind(SymbolKind.BUILDER_MACRO))
|
|
360
|
+
if result is None:
|
|
361
|
+
return None
|
|
362
|
+
ult_mod, ult_name, _bd = result
|
|
363
|
+
return macro_reg.get_builder_macro(ult_mod, ult_name)
|
|
364
|
+
|
|
365
|
+
def _handle_ctor(
|
|
366
|
+
self, var_name: str, call: TpyCall, macro_cls: type,
|
|
367
|
+
) -> None:
|
|
368
|
+
from ..macro_loader import validate_builder_macro
|
|
369
|
+
|
|
370
|
+
self._reject_active_reassignment(var_name, call.loc)
|
|
371
|
+
qname = f"{call.resolved_import[0]}.{call.resolved_import[1]}"
|
|
372
|
+
args = _build_macro_args(call.args, call.kwargs)
|
|
373
|
+
ctx_obj = BuilderContext(
|
|
374
|
+
expander=self, ctx=self.ctx,
|
|
375
|
+
call_loc=call.loc, function_being_traced=self.function_being_traced,
|
|
376
|
+
)
|
|
377
|
+
state = validate_builder_macro(macro_cls, ctx_obj, args, qname, call.loc)
|
|
378
|
+
handlers = _scan_handlers(macro_cls)
|
|
379
|
+
self._tracked[var_name] = _TrackedSymbol(
|
|
380
|
+
var_name=var_name, state=state, macro_qname=qname,
|
|
381
|
+
handlers=handlers,
|
|
382
|
+
)
|
|
383
|
+
self._all_tracked_names.add(var_name)
|
|
384
|
+
self._open_traces[var_name] = call.loc
|
|
385
|
+
|
|
386
|
+
# ------------------------------------------------------------------
|
|
387
|
+
# Method-call handling
|
|
388
|
+
# ------------------------------------------------------------------
|
|
389
|
+
|
|
390
|
+
def _handle_method_call(
|
|
391
|
+
self, stmt: TpyStmt, mcall: TpyMethodCall, lhs: str | None,
|
|
392
|
+
) -> Any:
|
|
393
|
+
if not isinstance(mcall.obj, TpyName):
|
|
394
|
+
return _NOT_HANDLED
|
|
395
|
+
sym = self._tracked.get(mcall.obj.name)
|
|
396
|
+
if sym is None:
|
|
397
|
+
return _NOT_HANDLED
|
|
398
|
+
spec = sym.handlers.get(mcall.method)
|
|
399
|
+
if spec is None:
|
|
400
|
+
raise SemanticError(
|
|
401
|
+
f"no @builder_method handler for '{sym.macro_qname}.{mcall.method}'",
|
|
402
|
+
mcall.loc,
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
from ..macro_loader import expand_builder_method
|
|
406
|
+
|
|
407
|
+
args = _build_macro_args(mcall.args, mcall.kwargs)
|
|
408
|
+
ctx_obj = BuilderContext(
|
|
409
|
+
expander=self, ctx=self.ctx,
|
|
410
|
+
call_loc=mcall.loc, function_being_traced=self.function_being_traced,
|
|
411
|
+
)
|
|
412
|
+
bound = spec.fn.__get__(sym.state, type(sym.state))
|
|
413
|
+
qname = f"{sym.macro_qname}.{mcall.method}"
|
|
414
|
+
|
|
415
|
+
if spec.kind == _KIND_METHOD:
|
|
416
|
+
expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
|
|
417
|
+
return _DROP
|
|
418
|
+
|
|
419
|
+
if spec.kind == _KIND_RETURNS:
|
|
420
|
+
if lhs is None:
|
|
421
|
+
raise SemanticError(
|
|
422
|
+
f"@builder_returns method '{qname}' must be assigned to a name",
|
|
423
|
+
mcall.loc,
|
|
424
|
+
)
|
|
425
|
+
# Run the reassignment check before invoking the handler so
|
|
426
|
+
# the diagnostic fires even when the handler would itself
|
|
427
|
+
# crash -- and so the parent's trace state isn't silently
|
|
428
|
+
# overwritten before the user-visible error.
|
|
429
|
+
self._reject_active_reassignment(lhs, mcall.loc)
|
|
430
|
+
child_state = expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
|
|
431
|
+
child_cls = spec.child_class
|
|
432
|
+
if child_cls is None or not isinstance(child_state, child_cls):
|
|
433
|
+
raise SemanticError(
|
|
434
|
+
f"@builder_returns({getattr(child_cls, '__name__', '?')}) "
|
|
435
|
+
f"method '{qname}' returned {type(child_state).__name__}",
|
|
436
|
+
mcall.loc,
|
|
437
|
+
)
|
|
438
|
+
child_handlers = _scan_handlers(child_cls)
|
|
439
|
+
self._tracked[lhs] = _TrackedSymbol(
|
|
440
|
+
var_name=lhs, state=child_state,
|
|
441
|
+
macro_qname=f"{sym.macro_qname}::{child_cls.__name__}",
|
|
442
|
+
handlers=child_handlers,
|
|
443
|
+
parent_var=sym.var_name,
|
|
444
|
+
)
|
|
445
|
+
self._all_tracked_names.add(lhs)
|
|
446
|
+
self._open_traces[lhs] = mcall.loc
|
|
447
|
+
return _DROP
|
|
448
|
+
|
|
449
|
+
# _KIND_TERMINAL: handler should call ctx.replace_call.
|
|
450
|
+
self._pending_replacement = None
|
|
451
|
+
result = expand_builder_method(bound, qname, ctx_obj, args, mcall.loc)
|
|
452
|
+
replacement = self._pending_replacement
|
|
453
|
+
self._pending_replacement = None
|
|
454
|
+
if replacement is None:
|
|
455
|
+
raise SemanticError(
|
|
456
|
+
f"@builder_terminal handler '{qname}' did not call "
|
|
457
|
+
f"ctx.replace_call(); the call site cannot be rewritten",
|
|
458
|
+
mcall.loc,
|
|
459
|
+
)
|
|
460
|
+
# Tracked symbol's trace is finished; remove from active tracking.
|
|
461
|
+
# Sub-builders spawned via @builder_returns from this symbol (or
|
|
462
|
+
# from any of those descendants) are closed alongside the root --
|
|
463
|
+
# they don't have their own terminal and contribute their state
|
|
464
|
+
# to the root's terminal handler. Walk the parent_var chain to
|
|
465
|
+
# find every descendant before mutating the dicts.
|
|
466
|
+
#
|
|
467
|
+
# Cost is O(D * N) where D is chain depth and N is the number of
|
|
468
|
+
# tracked symbols still alive: each iteration extends ``closing``
|
|
469
|
+
# by one depth level. Fine for argparse (max depth 3: parser ->
|
|
470
|
+
# subparsers_action -> sub_builder); a reverse parent->children
|
|
471
|
+
# map would flatten this to O(N) if deeper builder chains land.
|
|
472
|
+
closing = {sym.var_name}
|
|
473
|
+
changed = True
|
|
474
|
+
while changed:
|
|
475
|
+
changed = False
|
|
476
|
+
for name, ts in self._tracked.items():
|
|
477
|
+
if name in closing:
|
|
478
|
+
continue
|
|
479
|
+
if ts.parent_var in closing:
|
|
480
|
+
closing.add(name)
|
|
481
|
+
changed = True
|
|
482
|
+
for name in closing:
|
|
483
|
+
self._tracked.pop(name, None)
|
|
484
|
+
self._open_traces.pop(name, None)
|
|
485
|
+
rewritten = self._build_replacement_call(replacement, mcall.loc)
|
|
486
|
+
if isinstance(stmt, TpyAssign):
|
|
487
|
+
stmt.value = rewritten
|
|
488
|
+
return stmt
|
|
489
|
+
if isinstance(stmt, TpyVarDecl):
|
|
490
|
+
stmt.init = rewritten
|
|
491
|
+
return stmt
|
|
492
|
+
# bare call statement
|
|
493
|
+
new_stmt = TpyExprStmt(expr=rewritten)
|
|
494
|
+
new_stmt.loc = stmt.loc
|
|
495
|
+
return new_stmt
|
|
496
|
+
|
|
497
|
+
def _build_replacement_call(
|
|
498
|
+
self, rep: _PendingReplacement, loc: Any,
|
|
499
|
+
) -> TpyCall:
|
|
500
|
+
positional_exprs = [ma.expr for ma in rep.args.positional]
|
|
501
|
+
kwarg_exprs = {k: ma.expr for k, ma in rep.args.kwargs.items()}
|
|
502
|
+
call = TpyCall(
|
|
503
|
+
func=TpyName(rep.fn_name),
|
|
504
|
+
args=positional_exprs,
|
|
505
|
+
kwargs=kwarg_exprs,
|
|
506
|
+
)
|
|
507
|
+
call.loc = loc
|
|
508
|
+
return call
|
|
509
|
+
|
|
510
|
+
# ------------------------------------------------------------------
|
|
511
|
+
# BuilderContext-facing hooks
|
|
512
|
+
# ------------------------------------------------------------------
|
|
513
|
+
|
|
514
|
+
def fresh_module_name(self, hint: str) -> str:
|
|
515
|
+
"""Allocate a unique module-private name for a synthesized decl.
|
|
516
|
+
|
|
517
|
+
Counters live on SemanticContext so they're shared across all
|
|
518
|
+
builder-trace expansions in the same module -- otherwise two
|
|
519
|
+
functions both opening an ArgumentParser trace would each mint
|
|
520
|
+
the same suffix-1 record/function name and collide at codegen.
|
|
521
|
+
"""
|
|
522
|
+
counters = self.ctx.builder_trace_fresh_counters
|
|
523
|
+
n = counters.get(hint, 0) + 1
|
|
524
|
+
counters[hint] = n
|
|
525
|
+
return f"{_SYNTH_PREFIX}{hint}_{n}"
|
|
526
|
+
|
|
527
|
+
def emit_record(
|
|
528
|
+
self, name: str, fields: list[tuple[str, TpyType]],
|
|
529
|
+
methods: list[TpyFunction], loc: Any,
|
|
530
|
+
) -> TypeInfo:
|
|
531
|
+
"""Caveats: ``validate_record_inheritance`` and
|
|
532
|
+
``validate_value_type_fields`` run before any builder-trace
|
|
533
|
+
expansion, so synthesized records skip those passes -- inheritance
|
|
534
|
+
and ValueType-conformance constraints on emitted records are
|
|
535
|
+
currently unchecked. The current argparse use case (plain data
|
|
536
|
+
structs) doesn't hit either.
|
|
537
|
+
|
|
538
|
+
``methods`` may include any combination of methods; a default
|
|
539
|
+
positional ``__init__`` is auto-injected unless one is already
|
|
540
|
+
present in the list. This lets builder-trace macros emit
|
|
541
|
+
property forwarders / helper methods alongside the default init
|
|
542
|
+
without having to re-implement the init shape themselves.
|
|
543
|
+
"""
|
|
544
|
+
methods = list(methods)
|
|
545
|
+
if not any(m.name == "__init__" for m in methods):
|
|
546
|
+
methods.insert(0, _build_default_init(fields, loc))
|
|
547
|
+
record = _build_record(name, fields, methods, loc)
|
|
548
|
+
# Append to module so codegen sees it; register with the registrar
|
|
549
|
+
# so subsequent sema lookups find it.
|
|
550
|
+
self.module.records.append(record)
|
|
551
|
+
self.registrar.register_record(record)
|
|
552
|
+
# Promote the bare NominalType to qname-bearing form so type
|
|
553
|
+
# equality with the registered RecordInfo holds in compatibility
|
|
554
|
+
# checks (otherwise references via the bare type and via the
|
|
555
|
+
# registered type compare unequal even though both name "name").
|
|
556
|
+
from ..parse.resolve_refs import promote_bare_nominals
|
|
557
|
+
promoted = promote_bare_nominals(NominalType(name), self.ctx.registry)
|
|
558
|
+
return TypeInfo.from_tpy_type(promoted)
|
|
559
|
+
|
|
560
|
+
def emit_function(
|
|
561
|
+
self, name: str, params: list[tuple[str, TpyType]],
|
|
562
|
+
return_type: TpyType, body: list[TpyStmt], loc: Any,
|
|
563
|
+
) -> str:
|
|
564
|
+
"""Caveat: ``_normalize_function_info_refs`` runs in pass 2 of
|
|
565
|
+
analyze(); synthesized functions are added in passes 4 / 5.5
|
|
566
|
+
and skip that normalization, so ``FunctionInfo.params`` are
|
|
567
|
+
not wrapped with ``RefType`` for non-value parameter types.
|
|
568
|
+
Masked today because overload resolution unwraps refs on both
|
|
569
|
+
sides; any future check that distinguishes ``ListType`` from
|
|
570
|
+
``RefType(ListType)`` on registered params would expose this.
|
|
571
|
+
"""
|
|
572
|
+
# Returning a freshly constructed reference type requires Own[T] --
|
|
573
|
+
# synthesized parse functions always move ownership to the caller.
|
|
574
|
+
if not return_type.is_value_type() and not isinstance(return_type, OwnType):
|
|
575
|
+
return_type = OwnType(return_type)
|
|
576
|
+
body = list(body)
|
|
577
|
+
# Stmts coming from ast.quote() carry locs anchored to the
|
|
578
|
+
# fragment source, not the user module. Clear them so codegen
|
|
579
|
+
# doesn't try to look up the fragment's line numbers in main.py.
|
|
580
|
+
_strip_fragment_locs(body)
|
|
581
|
+
# Quoted-statement fragments leave TypeRefNodes on annotated
|
|
582
|
+
# decls / generic call_type / etc.; sema's pre-pass already ran
|
|
583
|
+
# by the time we're here, so resolve them now using the module's
|
|
584
|
+
# parser resolver. Mirrors what _finalize_function_refs does for
|
|
585
|
+
# quote_fun-produced functions.
|
|
586
|
+
resolver = getattr(self.ctx, "parser_resolver", None)
|
|
587
|
+
if resolver is not None:
|
|
588
|
+
from ..parse.resolve_refs import _walk_body
|
|
589
|
+
_walk_body(body, None, resolver)
|
|
590
|
+
func = TpyFunction(
|
|
591
|
+
name=name, params=list(params), return_type=return_type,
|
|
592
|
+
body=body,
|
|
593
|
+
)
|
|
594
|
+
func.loc = loc
|
|
595
|
+
self.module.functions.append(func)
|
|
596
|
+
self.registrar.register_function(func)
|
|
597
|
+
return name
|
|
598
|
+
|
|
599
|
+
def replace_call(
|
|
600
|
+
self, fn_name: str, args: MacroArgs, loc: Any,
|
|
601
|
+
) -> None:
|
|
602
|
+
if self._pending_replacement is not None:
|
|
603
|
+
raise SemanticError(
|
|
604
|
+
"ctx.replace_call() called more than once during a single "
|
|
605
|
+
"@builder_terminal expansion",
|
|
606
|
+
loc,
|
|
607
|
+
)
|
|
608
|
+
self._pending_replacement = _PendingReplacement(fn_name=fn_name, args=args)
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
def _build_record(
|
|
612
|
+
name: str, fields: list[tuple[str, TpyType]],
|
|
613
|
+
methods: list[TpyFunction], loc: Any,
|
|
614
|
+
) -> TpyRecord:
|
|
615
|
+
field_infos = [FieldInfo(name=fname, type=ftype) for fname, ftype in fields]
|
|
616
|
+
record = TpyRecord(name=name, fields=field_infos, methods=list(methods))
|
|
617
|
+
record.loc = loc
|
|
618
|
+
return record
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def _strip_fragment_locs(stmts: list[TpyStmt]) -> None:
|
|
622
|
+
"""Recursively clear ``loc`` on stmts produced by ``ast.quote()``.
|
|
623
|
+
|
|
624
|
+
Quoted-fragment stmts carry locs whose line numbers index the
|
|
625
|
+
fragment source, not the user module's source -- if those flow
|
|
626
|
+
through to codegen unchanged, ``emit_inline_comments`` indexes
|
|
627
|
+
out of bounds. Clearing matches the implicit contract for
|
|
628
|
+
``ast.*``-built stmts (which never set loc in the first place).
|
|
629
|
+
"""
|
|
630
|
+
for stmt in stmts:
|
|
631
|
+
stmt.loc = None
|
|
632
|
+
for nested in stmt.sub_bodies():
|
|
633
|
+
_strip_fragment_locs(nested)
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def _build_default_init(
|
|
637
|
+
fields: list[tuple[str, TpyType]], loc: Any,
|
|
638
|
+
) -> TpyFunction:
|
|
639
|
+
"""Build a positional ``__init__`` that assigns each field from a
|
|
640
|
+
same-named parameter.
|
|
641
|
+
|
|
642
|
+
Used by ``emit_record`` when the caller doesn't supply methods.
|
|
643
|
+
"""
|
|
644
|
+
from ..parse.nodes import TpyAssign, TpyFieldAccess, TpyName
|
|
645
|
+
from ..typesys import OwnType, UnionType
|
|
646
|
+
|
|
647
|
+
params: list[tuple[str, TpyType]] = []
|
|
648
|
+
body: list[Any] = []
|
|
649
|
+
for fname, ftype in fields:
|
|
650
|
+
# Union[A, B] non-value fields use the bare type as the param
|
|
651
|
+
# (pointer-variant convention) -- codegen expects the body's
|
|
652
|
+
# implicit assignment to lower through `to_value_variant`,
|
|
653
|
+
# which assumes a pointer-variant input. Wrapping in OwnType
|
|
654
|
+
# here renders the param as `value_variant&&` and breaks that
|
|
655
|
+
# body lowering. Mirrors how user-written ctors for Union-
|
|
656
|
+
# typed fields are spelled (`s: A | B`, not `s: Own[A | B]`).
|
|
657
|
+
if ftype.is_value_type() or isinstance(ftype, UnionType):
|
|
658
|
+
param_type = ftype
|
|
659
|
+
else:
|
|
660
|
+
param_type = OwnType(ftype)
|
|
661
|
+
params.append((fname, param_type))
|
|
662
|
+
body.append(TpyAssign(
|
|
663
|
+
target=TpyFieldAccess(obj=TpyName("self"), field=fname),
|
|
664
|
+
value=TpyName(fname),
|
|
665
|
+
))
|
|
666
|
+
func = TpyFunction(
|
|
667
|
+
name="__init__", params=params, return_type=VOID, body=body,
|
|
668
|
+
is_method=True, is_macro_generated=True, macro_origin="builder-trace",
|
|
669
|
+
)
|
|
670
|
+
func.loc = loc
|
|
671
|
+
return func
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
# Sentinel objects for _process_stmt return values.
|
|
675
|
+
class _DropMarker:
|
|
676
|
+
pass
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
class _NotHandledMarker:
|
|
680
|
+
pass
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
_DROP = _DropMarker()
|
|
684
|
+
_NOT_HANDLED = _NotHandledMarker()
|