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/repl.py
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython Interactive REPL
|
|
3
|
+
|
|
4
|
+
Provides an interactive Python-like experience with:
|
|
5
|
+
- Multi-line input support (for function/class definitions)
|
|
6
|
+
- Expression auto-printing (bare `5+3` prints the result)
|
|
7
|
+
- Error/panic recovery (failed statements don't accumulate)
|
|
8
|
+
- C++ compiler selection via --cxx: clang-repl (default), clang++, g++, zig
|
|
9
|
+
- Verbose mode: -v for timing, -vv for generated C++
|
|
10
|
+
- Trailing backslash continues to next line
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
import ast
|
|
15
|
+
import atexit
|
|
16
|
+
import difflib
|
|
17
|
+
import readline # For history support
|
|
18
|
+
import shutil
|
|
19
|
+
import sys
|
|
20
|
+
import tempfile
|
|
21
|
+
import time
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from .parse import ParseError, TpyExprStmt, TpyCoerce
|
|
25
|
+
from .sema import SemanticError, DiagnosticLevel
|
|
26
|
+
from .typesys import VoidType, is_any_str_type
|
|
27
|
+
from .type_def_registry import is_char_type
|
|
28
|
+
from .compiler import Compiler
|
|
29
|
+
from .codegen_cpp.context import get_include_path
|
|
30
|
+
from .repl_backends import (
|
|
31
|
+
REPLBackend, BackendResult, detect_backend, _fmt_ms,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class REPLSession:
|
|
36
|
+
"""Interactive TurboPython REPL session."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, verbose: int = 0, preload_files: list[Path] | None = None,
|
|
39
|
+
lib_dirs: list[Path] | None = None,
|
|
40
|
+
cxx: str = "auto"):
|
|
41
|
+
self.accumulated_lines: list[str] = []
|
|
42
|
+
self.verbose = verbose
|
|
43
|
+
self.preload_files = preload_files or []
|
|
44
|
+
self.lib_dirs = lib_dirs
|
|
45
|
+
self.temp_dir = Path(tempfile.mkdtemp(prefix="tpyc_repl_"))
|
|
46
|
+
self.prev_cpp_lines: list[str] = [] # For verbose diff
|
|
47
|
+
self._module_name = "repl"
|
|
48
|
+
self._cxx = cxx
|
|
49
|
+
self._backend: REPLBackend | None = None
|
|
50
|
+
atexit.register(self.cleanup)
|
|
51
|
+
|
|
52
|
+
def _preload_file(self, filepath: Path) -> bool:
|
|
53
|
+
"""Load and execute a file, accumulating its definitions.
|
|
54
|
+
|
|
55
|
+
Returns True on success, False on error.
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
source = filepath.read_text()
|
|
59
|
+
except FileNotFoundError:
|
|
60
|
+
print(f"Error: File not found: {filepath}", file=sys.stderr)
|
|
61
|
+
return False
|
|
62
|
+
except IOError as e:
|
|
63
|
+
print(f"Error reading {filepath}: {e}", file=sys.stderr)
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
# Try to compile and run the file
|
|
67
|
+
success, output = self._try_compile_and_run(source, maybe_auto_print=False)
|
|
68
|
+
|
|
69
|
+
if success:
|
|
70
|
+
# Accumulate all definitions from the file
|
|
71
|
+
if self._should_accumulate(source):
|
|
72
|
+
self.accumulated_lines.append(source)
|
|
73
|
+
else:
|
|
74
|
+
# For files with mixed content, extract just the definitions
|
|
75
|
+
try:
|
|
76
|
+
tree = ast.parse(source)
|
|
77
|
+
definitions = []
|
|
78
|
+
for stmt in tree.body:
|
|
79
|
+
if isinstance(stmt, (
|
|
80
|
+
ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef,
|
|
81
|
+
ast.Assign, ast.AnnAssign, ast.AugAssign,
|
|
82
|
+
ast.Import, ast.ImportFrom, ast.TypeAlias,
|
|
83
|
+
)):
|
|
84
|
+
# Get the source lines for this statement
|
|
85
|
+
start = stmt.lineno - 1
|
|
86
|
+
end = stmt.end_lineno if stmt.end_lineno else stmt.lineno
|
|
87
|
+
lines = source.split('\n')[start:end]
|
|
88
|
+
definitions.append('\n'.join(lines))
|
|
89
|
+
if definitions:
|
|
90
|
+
self.accumulated_lines.extend(definitions)
|
|
91
|
+
except SyntaxError:
|
|
92
|
+
pass
|
|
93
|
+
if output:
|
|
94
|
+
print(output, end="")
|
|
95
|
+
return True
|
|
96
|
+
else:
|
|
97
|
+
print(output, end="", file=sys.stderr)
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
def _setup_readline(self) -> None:
|
|
101
|
+
"""Configure readline for history."""
|
|
102
|
+
history_path = Path.home() / ".tpyc_history"
|
|
103
|
+
try:
|
|
104
|
+
readline.read_history_file(history_path)
|
|
105
|
+
except FileNotFoundError:
|
|
106
|
+
pass
|
|
107
|
+
readline.set_history_length(1000)
|
|
108
|
+
atexit.register(readline.write_history_file, history_path)
|
|
109
|
+
|
|
110
|
+
def _read_paste_mode(self) -> str | None:
|
|
111
|
+
"""Read multiline input in paste mode. Returns None if cancelled."""
|
|
112
|
+
print("Paste mode: paste your code, then Ctrl+D to execute (Ctrl+C to cancel)")
|
|
113
|
+
lines = []
|
|
114
|
+
try:
|
|
115
|
+
while True:
|
|
116
|
+
try:
|
|
117
|
+
line = input("... ")
|
|
118
|
+
lines.append(line)
|
|
119
|
+
except EOFError:
|
|
120
|
+
break
|
|
121
|
+
except KeyboardInterrupt:
|
|
122
|
+
print("\nPaste cancelled.")
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
print() # Newline after Ctrl+D
|
|
126
|
+
return "\n".join(lines)
|
|
127
|
+
|
|
128
|
+
def run(self) -> int:
|
|
129
|
+
"""Main REPL loop. Returns exit code."""
|
|
130
|
+
# Detect and start backend
|
|
131
|
+
self._backend = detect_backend(
|
|
132
|
+
self._cxx, self.temp_dir, self._module_name, verbose=self.verbose,
|
|
133
|
+
)
|
|
134
|
+
from . import __version__
|
|
135
|
+
print(f"TurboPython REPL v{__version__} (backend: {self._backend.name})")
|
|
136
|
+
print("Variables, functions, and classes are remembered between inputs.")
|
|
137
|
+
print("Empty line unindents (or ends block at col 0). Trailing \\ continues input. Ctrl+D to exit.")
|
|
138
|
+
print("Type .paste (or .p) for multiline input mode.")
|
|
139
|
+
|
|
140
|
+
self._backend.startup()
|
|
141
|
+
if self.verbose >= 1:
|
|
142
|
+
print(f"Build dir: {self.temp_dir}/")
|
|
143
|
+
if hasattr(self._backend, 'pch_cache_dir'):
|
|
144
|
+
print(f"PCH cache: {self._backend.pch_cache_dir}/")
|
|
145
|
+
|
|
146
|
+
# Preload files if specified
|
|
147
|
+
for filepath in self.preload_files:
|
|
148
|
+
print(f"Loading {filepath}...")
|
|
149
|
+
if not self._preload_file(filepath):
|
|
150
|
+
return 1
|
|
151
|
+
|
|
152
|
+
# Auto-import tpy types if no files were preloaded
|
|
153
|
+
if not self.preload_files:
|
|
154
|
+
self.accumulated_lines.append("from tpy import *")
|
|
155
|
+
print("(imported tpy types: Int32, Char, Array, Span, Ptr, ...)")
|
|
156
|
+
|
|
157
|
+
# Setup readline
|
|
158
|
+
self._setup_readline()
|
|
159
|
+
|
|
160
|
+
while True:
|
|
161
|
+
try:
|
|
162
|
+
line = input(">>> ")
|
|
163
|
+
|
|
164
|
+
# Handle special commands
|
|
165
|
+
stripped = line.strip()
|
|
166
|
+
if stripped in ("exit", "quit"):
|
|
167
|
+
break
|
|
168
|
+
if not stripped:
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
# Dot commands
|
|
172
|
+
if stripped.startswith("."):
|
|
173
|
+
if stripped in (".paste", ".p"):
|
|
174
|
+
pasted = self._read_paste_mode()
|
|
175
|
+
if pasted and pasted.strip():
|
|
176
|
+
self._process_input(pasted)
|
|
177
|
+
else:
|
|
178
|
+
print(f"Unknown command: {stripped.split()[0]}")
|
|
179
|
+
continue
|
|
180
|
+
|
|
181
|
+
# Alt+Enter inserts literal newlines into readline buffer,
|
|
182
|
+
# so input() may return multiline strings directly
|
|
183
|
+
full_input = line
|
|
184
|
+
|
|
185
|
+
# Handle backslash continuation (fallback for terminals
|
|
186
|
+
# where Alt+Enter doesn't work)
|
|
187
|
+
while full_input.rstrip().endswith("\\"):
|
|
188
|
+
full_input = full_input.rstrip()[:-1] # Remove trailing backslash
|
|
189
|
+
try:
|
|
190
|
+
cont_line = input("... ")
|
|
191
|
+
full_input += "\n" + cont_line
|
|
192
|
+
except EOFError:
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
# Check for multi-line continuation (incomplete syntax)
|
|
196
|
+
if self._needs_continuation(full_input):
|
|
197
|
+
in_block = full_input.rstrip().endswith(":")
|
|
198
|
+
indent_level = 1 # Start with one indent level
|
|
199
|
+
cont_stripped = ""
|
|
200
|
+
while True:
|
|
201
|
+
try:
|
|
202
|
+
indent = "\t" * indent_level
|
|
203
|
+
cont_line = input("... " + indent)
|
|
204
|
+
# Empty line: reduce indent or end block
|
|
205
|
+
if not cont_line.strip():
|
|
206
|
+
if indent_level > 1:
|
|
207
|
+
indent_level -= 1
|
|
208
|
+
continue # Don't add empty line, just reduce indent
|
|
209
|
+
else:
|
|
210
|
+
break # At first block level (or zero), end block
|
|
211
|
+
# else/elif/except/finally belong at the outer
|
|
212
|
+
# block level (no extra indent)
|
|
213
|
+
cont_stripped = cont_line.strip()
|
|
214
|
+
if cont_stripped.split()[0].rstrip(":") in (
|
|
215
|
+
"else", "elif", "except", "finally",
|
|
216
|
+
):
|
|
217
|
+
full_input += "\n" + cont_line.strip()
|
|
218
|
+
else:
|
|
219
|
+
full_input += "\n" + indent + cont_line
|
|
220
|
+
except EOFError:
|
|
221
|
+
break
|
|
222
|
+
# For blocks (def/class/if/etc), require empty line to end
|
|
223
|
+
# For other continuations (unclosed parens), end when complete
|
|
224
|
+
if not in_block and not self._needs_continuation(full_input):
|
|
225
|
+
break
|
|
226
|
+
# Adjust indent based on what user typed
|
|
227
|
+
if cont_stripped.endswith(":"):
|
|
228
|
+
indent_level += 1
|
|
229
|
+
|
|
230
|
+
self._process_input(full_input)
|
|
231
|
+
|
|
232
|
+
except EOFError:
|
|
233
|
+
print()
|
|
234
|
+
break
|
|
235
|
+
except KeyboardInterrupt:
|
|
236
|
+
print()
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
return 0
|
|
240
|
+
|
|
241
|
+
def _needs_continuation(self, source: str) -> bool:
|
|
242
|
+
"""Check if input needs continuation lines."""
|
|
243
|
+
stripped = source.rstrip()
|
|
244
|
+
|
|
245
|
+
# Ends with colon (def, class, if, for, while, etc.)
|
|
246
|
+
if stripped.endswith(":"):
|
|
247
|
+
return True
|
|
248
|
+
|
|
249
|
+
# Check for unclosed brackets/parens
|
|
250
|
+
opens = source.count("(") + source.count("[") + source.count("{")
|
|
251
|
+
closes = source.count(")") + source.count("]") + source.count("}")
|
|
252
|
+
if opens > closes:
|
|
253
|
+
return True
|
|
254
|
+
|
|
255
|
+
# Check for incomplete block (has def/class/if/etc but only header)
|
|
256
|
+
try:
|
|
257
|
+
ast.parse(source)
|
|
258
|
+
return False
|
|
259
|
+
except SyntaxError:
|
|
260
|
+
return True
|
|
261
|
+
|
|
262
|
+
def _get_indent_for_continuation(self, source: str) -> str:
|
|
263
|
+
"""Calculate indentation for the next continuation line."""
|
|
264
|
+
lines = source.split("\n")
|
|
265
|
+
last_line = lines[-1]
|
|
266
|
+
|
|
267
|
+
# Get current indentation of last line
|
|
268
|
+
current_indent = len(last_line) - len(last_line.lstrip())
|
|
269
|
+
|
|
270
|
+
# If last line ends with ':', increase indent
|
|
271
|
+
if last_line.rstrip().endswith(":"):
|
|
272
|
+
return " " * (current_indent + 4)
|
|
273
|
+
|
|
274
|
+
# Otherwise, maintain the same indentation as the last non-empty line
|
|
275
|
+
for line in reversed(lines):
|
|
276
|
+
if line.strip():
|
|
277
|
+
return " " * (len(line) - len(line.lstrip()))
|
|
278
|
+
|
|
279
|
+
return ""
|
|
280
|
+
|
|
281
|
+
def _is_bare_expression(self, source: str) -> bool:
|
|
282
|
+
"""Check if input is a single bare expression (not a print call)."""
|
|
283
|
+
try:
|
|
284
|
+
tree = ast.parse(source)
|
|
285
|
+
if len(tree.body) != 1:
|
|
286
|
+
return False
|
|
287
|
+
stmt = tree.body[0]
|
|
288
|
+
if not isinstance(stmt, ast.Expr):
|
|
289
|
+
return False
|
|
290
|
+
# print() calls are already printing, don't wrap
|
|
291
|
+
if isinstance(stmt.value, ast.Call):
|
|
292
|
+
if isinstance(stmt.value.func, ast.Name):
|
|
293
|
+
if stmt.value.func.id == "print":
|
|
294
|
+
return False
|
|
295
|
+
return True
|
|
296
|
+
except SyntaxError:
|
|
297
|
+
return False
|
|
298
|
+
|
|
299
|
+
def _should_accumulate(self, source: str) -> bool:
|
|
300
|
+
"""Check if input should be accumulated for future compilations.
|
|
301
|
+
|
|
302
|
+
Accumulates definitions/assignments. Skips inputs containing any
|
|
303
|
+
expression-statement call (`print(x)`, `sys.stderr.write(...)`,
|
|
304
|
+
`f.write(...)`, etc.) -- their side effects shouldn't be replayed.
|
|
305
|
+
"""
|
|
306
|
+
try:
|
|
307
|
+
tree = ast.parse(source)
|
|
308
|
+
if not tree.body:
|
|
309
|
+
return False
|
|
310
|
+
|
|
311
|
+
for stmt in tree.body:
|
|
312
|
+
if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call):
|
|
313
|
+
return False
|
|
314
|
+
|
|
315
|
+
return True
|
|
316
|
+
except SyntaxError:
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
def _process_input(self, source: str) -> None:
|
|
320
|
+
"""Process a single input and optionally accumulate if successful."""
|
|
321
|
+
# Check if this might be an expression that should auto-print
|
|
322
|
+
# (actual type checking happens in _try_compile_and_run)
|
|
323
|
+
maybe_auto_print = self._is_bare_expression(source)
|
|
324
|
+
|
|
325
|
+
success, output = self._try_compile_and_run(source, maybe_auto_print)
|
|
326
|
+
|
|
327
|
+
if success:
|
|
328
|
+
# Only accumulate definitions/assignments, not side-effect statements
|
|
329
|
+
if self._should_accumulate(source):
|
|
330
|
+
self.accumulated_lines.append(source)
|
|
331
|
+
if output:
|
|
332
|
+
print(output, end="")
|
|
333
|
+
else:
|
|
334
|
+
# Show error, don't accumulate
|
|
335
|
+
print(output, end="", file=sys.stderr)
|
|
336
|
+
|
|
337
|
+
def _try_compile_and_run(
|
|
338
|
+
self, new_source: str, maybe_auto_print: bool = False
|
|
339
|
+
) -> tuple[bool, str]:
|
|
340
|
+
"""Attempt to compile accumulated + new source, run it.
|
|
341
|
+
|
|
342
|
+
Returns (success, output) where output is either the program output
|
|
343
|
+
or the error message.
|
|
344
|
+
"""
|
|
345
|
+
t_start = time.monotonic()
|
|
346
|
+
|
|
347
|
+
all_lines = self.accumulated_lines + [new_source]
|
|
348
|
+
combined = "\n".join(all_lines)
|
|
349
|
+
|
|
350
|
+
# Ensure main() is always generated
|
|
351
|
+
# (typed variable declarations become globals, not main() body)
|
|
352
|
+
combined += "\n0 # repl-noop"
|
|
353
|
+
|
|
354
|
+
# -v: show accumulated tpy source being compiled
|
|
355
|
+
source_output = ""
|
|
356
|
+
if self.verbose >= 1:
|
|
357
|
+
for line in all_lines:
|
|
358
|
+
for sub in line.split("\n"):
|
|
359
|
+
source_output += f" [tpy] {sub}\n"
|
|
360
|
+
|
|
361
|
+
# Compile via Compiler.from_source (supports multi-module imports)
|
|
362
|
+
try:
|
|
363
|
+
compiler = Compiler.from_source(
|
|
364
|
+
combined, self._module_name, lib_dirs=self.lib_dirs
|
|
365
|
+
)
|
|
366
|
+
compiler.allow_top_level_error_unwrap = True
|
|
367
|
+
compiled_modules = compiler.compile()
|
|
368
|
+
except ParseError as e:
|
|
369
|
+
return False, source_output + f"Parse error: {e}\n"
|
|
370
|
+
except SyntaxError as e:
|
|
371
|
+
return False, source_output + f"Syntax error: {e.msg} at line {e.lineno}\n"
|
|
372
|
+
except SemanticError as e:
|
|
373
|
+
return False, source_output + f"{e.format('repl')}\n"
|
|
374
|
+
except Exception as e:
|
|
375
|
+
return False, source_output + f"Compile error: {e}\n"
|
|
376
|
+
|
|
377
|
+
t_compile = time.monotonic() - t_start
|
|
378
|
+
|
|
379
|
+
# Find the entry module
|
|
380
|
+
entry_module = next(m for m in compiled_modules if m.is_entry_point)
|
|
381
|
+
module = entry_module.ast
|
|
382
|
+
analyzer = entry_module.analyzer
|
|
383
|
+
|
|
384
|
+
# Check if we should auto-print the expression
|
|
385
|
+
# The second-to-last statement is the user's input (last is the noop)
|
|
386
|
+
is_str_or_char = False
|
|
387
|
+
if maybe_auto_print and len(module.top_level_stmts) >= 2:
|
|
388
|
+
user_stmt = module.top_level_stmts[-2]
|
|
389
|
+
if isinstance(user_stmt, TpyExprStmt):
|
|
390
|
+
expr_type = analyzer.get_expr_type(user_stmt.expr)
|
|
391
|
+
# Only wrap if the expression has a non-void type
|
|
392
|
+
if expr_type is not None and not isinstance(expr_type, VoidType):
|
|
393
|
+
# Track if we're printing a string/char for post-processing
|
|
394
|
+
is_str_or_char = is_any_str_type(expr_type) or is_char_type(expr_type)
|
|
395
|
+
|
|
396
|
+
# For @error_return calls, unwrap into a temp first
|
|
397
|
+
# so the error check happens at statement level
|
|
398
|
+
expr = user_stmt.expr
|
|
399
|
+
while isinstance(expr, TpyCoerce):
|
|
400
|
+
expr = expr.expr
|
|
401
|
+
fi = getattr(expr, 'resolved_function_info', None)
|
|
402
|
+
is_error_return = fi is not None and fi.error_return_type is not None
|
|
403
|
+
if is_error_return:
|
|
404
|
+
wrapped_source = f"__repl_val = {new_source.strip()}\nprint(__repl_val)"
|
|
405
|
+
else:
|
|
406
|
+
wrapped_source = f"print({new_source.strip()})"
|
|
407
|
+
combined = "\n".join(self.accumulated_lines + [wrapped_source])
|
|
408
|
+
combined += "\n0 # repl-noop"
|
|
409
|
+
try:
|
|
410
|
+
compiler = Compiler.from_source(
|
|
411
|
+
combined, self._module_name, lib_dirs=self.lib_dirs
|
|
412
|
+
)
|
|
413
|
+
compiler.allow_top_level_error_unwrap = True
|
|
414
|
+
compiled_modules = compiler.compile()
|
|
415
|
+
entry_module = next(m for m in compiled_modules if m.is_entry_point)
|
|
416
|
+
module = entry_module.ast
|
|
417
|
+
analyzer = entry_module.analyzer
|
|
418
|
+
except (ParseError, SyntaxError, SemanticError):
|
|
419
|
+
is_str_or_char = False # Fall back to original if wrapping fails
|
|
420
|
+
|
|
421
|
+
# Show diagnostics and check for errors
|
|
422
|
+
diag_output = ""
|
|
423
|
+
has_errors = False
|
|
424
|
+
for diag in analyzer.diagnostics:
|
|
425
|
+
if diag.level in (DiagnosticLevel.WARNING, DiagnosticLevel.ERROR):
|
|
426
|
+
diag_output += f"{diag.format('repl')}\n"
|
|
427
|
+
if diag.level == DiagnosticLevel.ERROR:
|
|
428
|
+
has_errors = True
|
|
429
|
+
if has_errors:
|
|
430
|
+
return diag_output.rstrip()
|
|
431
|
+
|
|
432
|
+
# Generate code for all modules
|
|
433
|
+
t_codegen_start = time.monotonic()
|
|
434
|
+
all_hpp_paths: list[Path] = []
|
|
435
|
+
all_cpp_paths: list[Path] = []
|
|
436
|
+
all_cpp_code: list[str] = []
|
|
437
|
+
all_hpp_code: list[str] = []
|
|
438
|
+
for mod in compiled_modules:
|
|
439
|
+
hpp_code, cpp_code = compiler.generate_code_to_strings(mod)
|
|
440
|
+
|
|
441
|
+
# Write files matching the include path the codegen emits
|
|
442
|
+
include_path = get_include_path(mod.name)
|
|
443
|
+
if include_path is not None:
|
|
444
|
+
# e.g. "tpystd/tpy.hpp" -> write to {temp}/tpystd/tpy.{hpp,cpp}
|
|
445
|
+
rel = Path(include_path)
|
|
446
|
+
hpp_path = self.temp_dir / rel
|
|
447
|
+
cpp_path = self.temp_dir / rel.with_suffix('.cpp')
|
|
448
|
+
hpp_path.parent.mkdir(parents=True, exist_ok=True)
|
|
449
|
+
else:
|
|
450
|
+
mod_parts = mod.name.split('.')
|
|
451
|
+
if len(mod_parts) > 1:
|
|
452
|
+
hpp_subdir = self.temp_dir / Path(*mod_parts[:-1])
|
|
453
|
+
hpp_subdir.mkdir(parents=True, exist_ok=True)
|
|
454
|
+
hpp_path = hpp_subdir / f"{mod_parts[-1]}.hpp"
|
|
455
|
+
cpp_path = hpp_subdir / f"{mod_parts[-1]}.cpp"
|
|
456
|
+
else:
|
|
457
|
+
hpp_path = self.temp_dir / f"{mod.name}.hpp"
|
|
458
|
+
cpp_path = self.temp_dir / f"{mod.name}.cpp"
|
|
459
|
+
|
|
460
|
+
hpp_path.write_text(hpp_code)
|
|
461
|
+
cpp_path.write_text(cpp_code)
|
|
462
|
+
all_hpp_paths.append(hpp_path)
|
|
463
|
+
all_cpp_paths.append(cpp_path)
|
|
464
|
+
all_hpp_code.append(hpp_code)
|
|
465
|
+
all_cpp_code.append(cpp_code)
|
|
466
|
+
|
|
467
|
+
t_codegen = time.monotonic() - t_codegen_start
|
|
468
|
+
|
|
469
|
+
# -vv: show diff of generated C++ (entry module only)
|
|
470
|
+
verbose_output = ""
|
|
471
|
+
if self.verbose >= 2:
|
|
472
|
+
entry_cpp_code = all_cpp_code[-1]
|
|
473
|
+
current_lines = []
|
|
474
|
+
lines = [line.strip() for line in entry_cpp_code.split("\n") if line.strip()]
|
|
475
|
+
for i, stripped in enumerate(lines):
|
|
476
|
+
if stripped.startswith("//") or stripped.startswith("#"):
|
|
477
|
+
continue
|
|
478
|
+
if stripped in ("return 0;", "0;", "int main() {"):
|
|
479
|
+
continue
|
|
480
|
+
if stripped == "}" and i == len(lines) - 1:
|
|
481
|
+
continue
|
|
482
|
+
current_lines.append(stripped)
|
|
483
|
+
|
|
484
|
+
diff = difflib.unified_diff(self.prev_cpp_lines, current_lines, lineterm="", n=0)
|
|
485
|
+
new_lines = [line[1:] for line in diff if line.startswith("+") and not line.startswith("+++")]
|
|
486
|
+
|
|
487
|
+
if new_lines:
|
|
488
|
+
verbose_output = " [C++] " + "\n [C++] ".join(new_lines) + "\n"
|
|
489
|
+
|
|
490
|
+
self.prev_cpp_lines = current_lines
|
|
491
|
+
|
|
492
|
+
# Execute via backend
|
|
493
|
+
result = self._backend.execute(all_hpp_code, all_cpp_code, all_hpp_paths, all_cpp_paths)
|
|
494
|
+
|
|
495
|
+
if not result.success:
|
|
496
|
+
error_msg = result.stderr or "Unknown error\n"
|
|
497
|
+
return False, source_output + error_msg
|
|
498
|
+
|
|
499
|
+
# Surface anything the program wrote to stderr (sys.stderr.write, ...)
|
|
500
|
+
# to the REPL host's stderr; Python's interactive interpreter does the
|
|
501
|
+
# same. Compiler / runtime errors take the not-success path above.
|
|
502
|
+
if result.stderr:
|
|
503
|
+
sys.stderr.write(result.stderr)
|
|
504
|
+
sys.stderr.flush()
|
|
505
|
+
|
|
506
|
+
# For strings/chars, wrap output in quotes like Python's REPL
|
|
507
|
+
program_output = result.stdout
|
|
508
|
+
if is_str_or_char and program_output:
|
|
509
|
+
program_output = "'" + program_output.rstrip("\n") + "'\n"
|
|
510
|
+
|
|
511
|
+
# -v: show timing
|
|
512
|
+
timing_output = ""
|
|
513
|
+
if self.verbose >= 1:
|
|
514
|
+
t_total = time.monotonic() - t_start
|
|
515
|
+
build_str = _fmt_ms(result.t_build) if not result.build_cached else "cached"
|
|
516
|
+
timing_output = (
|
|
517
|
+
f" [{_fmt_ms(t_total)}] compile: {_fmt_ms(t_compile)} "
|
|
518
|
+
f"build: {build_str} "
|
|
519
|
+
f"run: {_fmt_ms(result.t_run)}\n"
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
return True, source_output + verbose_output + timing_output + diag_output + program_output
|
|
523
|
+
|
|
524
|
+
def cleanup(self) -> None:
|
|
525
|
+
"""Remove temp directory and stop backend on exit."""
|
|
526
|
+
if self._backend:
|
|
527
|
+
self._backend.cleanup()
|
|
528
|
+
if self.temp_dir.exists():
|
|
529
|
+
shutil.rmtree(self.temp_dir, ignore_errors=True)
|