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/cli.py
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPython CLI
|
|
3
|
+
|
|
4
|
+
Two entry points share this module:
|
|
5
|
+
|
|
6
|
+
tpy -- user-facing runner (default: run script, or REPL with no args)
|
|
7
|
+
tpyc -- compiler (default: emit .hpp/.cpp)
|
|
8
|
+
|
|
9
|
+
Both accept the same flags; only the default action differs.
|
|
10
|
+
|
|
11
|
+
Usage (tpy -- runner):
|
|
12
|
+
tpy # Start interactive REPL (auto-detect backend)
|
|
13
|
+
tpy input.py # Run the program
|
|
14
|
+
tpy -c "print(1 + 2)" # Run an inline snippet
|
|
15
|
+
tpy -b input.py # Compile and build binary (no run)
|
|
16
|
+
tpy --dump-code input.py # Print generated C++ to stdout
|
|
17
|
+
|
|
18
|
+
Usage (tpyc -- compiler):
|
|
19
|
+
tpyc input.py # Compile to C++ in __tpyc__/
|
|
20
|
+
tpyc input.py -o out/ # Compile to C++ in out/
|
|
21
|
+
tpyc input.py --build # Compile to C++ and build binary
|
|
22
|
+
tpyc input.py --exec # Compile, build, and run
|
|
23
|
+
tpyc input.py -x -- a b # Run with program args (sys.argv[1:] = ["a","b"])
|
|
24
|
+
tpyc --exec <<EOF # Read from stdin, build, and run
|
|
25
|
+
tpyc --dump-code <<EOF # Print generated C++ to stdout
|
|
26
|
+
tpyc --repl # Start interactive REPL (auto-detect backend)
|
|
27
|
+
tpyc --repl --cxx gcc # Force gcc backend
|
|
28
|
+
tpyc --repl file.py # Load file then start REPL
|
|
29
|
+
tpyc --repl -v # REPL with timing
|
|
30
|
+
tpyc --repl -vv # REPL with timing + generated C++
|
|
31
|
+
|
|
32
|
+
For tpyc, program arguments for --exec must be passed after `--` so tpyc's
|
|
33
|
+
own options can appear in any position (e.g. `tpyc foo.py -o out/ -x`).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
import argparse
|
|
38
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
39
|
+
import os
|
|
40
|
+
import subprocess
|
|
41
|
+
import sys
|
|
42
|
+
import tempfile
|
|
43
|
+
import time
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
|
|
46
|
+
from .parse import ParseError
|
|
47
|
+
from .sema import SemanticError, DiagnosticLevel
|
|
48
|
+
from .codegen_cpp import CodeGenOptions, CodeGenError
|
|
49
|
+
from .compiler import (
|
|
50
|
+
Compiler, CompileError, CompilerNotFoundError, BuildLayout, CppCompilerConfig,
|
|
51
|
+
DEFAULT_INT_CHOICES, list_compilers, get_or_build_pch,
|
|
52
|
+
)
|
|
53
|
+
from . import __version__, get_git_commit, get_runtime_dir, get_lib_dir, get_docs_dir
|
|
54
|
+
from .frontend_plugin import (
|
|
55
|
+
FrontendPluginError, FrontendRegistry, resolve_plugin_class,
|
|
56
|
+
route_dsl_opts,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _fmt_ms(seconds: float) -> str:
|
|
61
|
+
"""Format seconds as a human-readable duration."""
|
|
62
|
+
ms = seconds * 1000
|
|
63
|
+
if ms < 1000:
|
|
64
|
+
return f"{ms:.0f}ms"
|
|
65
|
+
return f"{ms / 1000:.1f}s"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _print_info(prog_name: str) -> None:
|
|
69
|
+
"""Print compiler version, paths, and environment info."""
|
|
70
|
+
commit = get_git_commit()
|
|
71
|
+
print(f"{prog_name} {__version__} ({commit})")
|
|
72
|
+
print()
|
|
73
|
+
|
|
74
|
+
# Paths
|
|
75
|
+
pkg_dir = Path(__file__).parent
|
|
76
|
+
lib_dir = get_lib_dir()
|
|
77
|
+
runtime_dir = get_runtime_dir()
|
|
78
|
+
docs_dir = get_docs_dir()
|
|
79
|
+
print(f"compiler: {pkg_dir}")
|
|
80
|
+
print(f"lib: {lib_dir / 'tpy'}")
|
|
81
|
+
print(f"runtime: {runtime_dir}")
|
|
82
|
+
print(f"docs: {docs_dir}")
|
|
83
|
+
print()
|
|
84
|
+
|
|
85
|
+
# C++ compiler
|
|
86
|
+
try:
|
|
87
|
+
config = CppCompilerConfig.from_env(cxx="auto")
|
|
88
|
+
cxx_desc = config.compiler_name
|
|
89
|
+
if config.ccache:
|
|
90
|
+
cxx_desc += " + ccache"
|
|
91
|
+
print(f"cxx: {cxx_desc} ({' '.join(config.compiler)})")
|
|
92
|
+
except CompilerNotFoundError:
|
|
93
|
+
print("cxx: not found")
|
|
94
|
+
print()
|
|
95
|
+
|
|
96
|
+
# Python
|
|
97
|
+
print(f"python: {sys.version.split()[0]} ({sys.executable})")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ProgressPrinter:
|
|
101
|
+
"""Prints build progress lines to stderr."""
|
|
102
|
+
|
|
103
|
+
def __init__(self, enabled: bool = True):
|
|
104
|
+
self.enabled = enabled
|
|
105
|
+
|
|
106
|
+
def _write(self, msg: str) -> None:
|
|
107
|
+
if not self.enabled:
|
|
108
|
+
return
|
|
109
|
+
sys.stderr.write(msg)
|
|
110
|
+
sys.stderr.flush()
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def _module_path(name: str) -> str:
|
|
114
|
+
"""Convert dot-separated module name to path format."""
|
|
115
|
+
return name.replace('.', '/')
|
|
116
|
+
|
|
117
|
+
def header(self, config: CppCompilerConfig | None = None,
|
|
118
|
+
release: bool = False, n_jobs: int = 1) -> None:
|
|
119
|
+
if not self.enabled:
|
|
120
|
+
return
|
|
121
|
+
if config is not None:
|
|
122
|
+
variant = "release" if release else "debug"
|
|
123
|
+
cxx = config.compiler_name
|
|
124
|
+
if config.ccache:
|
|
125
|
+
cxx += " + ccache"
|
|
126
|
+
job_s = "job" if n_jobs == 1 else "jobs"
|
|
127
|
+
sys.stderr.write(f"TurboPython v{__version__} ({cxx}, {variant}, {n_jobs} {job_s})\n")
|
|
128
|
+
else:
|
|
129
|
+
sys.stderr.write(f"TurboPython v{__version__}\n")
|
|
130
|
+
sys.stderr.flush()
|
|
131
|
+
|
|
132
|
+
def analyzed(self, user_modules: list[str], n_stdlib: int,
|
|
133
|
+
n_warnings: int, elapsed: float) -> None:
|
|
134
|
+
n_total = len(user_modules) + n_stdlib
|
|
135
|
+
self._write(f" analyzed {n_total} modules ({_fmt_ms(elapsed)})\n")
|
|
136
|
+
for i, name in enumerate(user_modules):
|
|
137
|
+
is_last = i == len(user_modules) - 1
|
|
138
|
+
suffix = f" (+ {n_stdlib} stdlib)\n" if is_last and n_stdlib else "\n"
|
|
139
|
+
self._write(f" {self._module_path(name)}.py{suffix}")
|
|
140
|
+
if n_warnings:
|
|
141
|
+
w = "warning" if n_warnings == 1 else "warnings"
|
|
142
|
+
self._write(f" {n_warnings} {w}\n")
|
|
143
|
+
|
|
144
|
+
def pch(self, elapsed: float) -> None:
|
|
145
|
+
if elapsed >= 0.1:
|
|
146
|
+
self._write(f" precompiled tpy.hpp ({_fmt_ms(elapsed)})\n")
|
|
147
|
+
|
|
148
|
+
def translated(self, name: str, elapsed: float) -> None:
|
|
149
|
+
self._write(f" translated {self._module_path(name)}.py ({_fmt_ms(elapsed)})\n")
|
|
150
|
+
|
|
151
|
+
def compiled(self, name: str, elapsed: float) -> None:
|
|
152
|
+
self._write(f" compiled {name} ({_fmt_ms(elapsed)})\n")
|
|
153
|
+
|
|
154
|
+
def linked(self, name: str, elapsed: float) -> None:
|
|
155
|
+
self._write(f" linked {name} ({_fmt_ms(elapsed)})\n")
|
|
156
|
+
|
|
157
|
+
def separator(self) -> None:
|
|
158
|
+
self._write("-- \n")
|
|
159
|
+
|
|
160
|
+
def summary(self, n_modules: int,
|
|
161
|
+
t_compile: float, t_codegen: float, t_build: float) -> None:
|
|
162
|
+
if not self.enabled:
|
|
163
|
+
return
|
|
164
|
+
total = t_compile + t_codegen + t_build
|
|
165
|
+
sys.stderr.write(
|
|
166
|
+
f"{n_modules} modules compiled in {_fmt_ms(total)}"
|
|
167
|
+
f" (py {_fmt_ms(t_compile)}, codegen {_fmt_ms(t_codegen)},"
|
|
168
|
+
f" build {_fmt_ms(t_build)})\n"
|
|
169
|
+
)
|
|
170
|
+
sys.stderr.flush()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _timed_run(cmd: list[str]) -> tuple[subprocess.CompletedProcess[str], float]:
|
|
174
|
+
"""Run a command and return (result, elapsed_seconds)."""
|
|
175
|
+
t = time.monotonic()
|
|
176
|
+
r = subprocess.run(cmd, capture_output=True, text=True)
|
|
177
|
+
return r, time.monotonic() - t
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_module_name(input_path: Path,
|
|
181
|
+
extra_extensions: frozenset[str] = frozenset()) -> str:
|
|
182
|
+
"""Get module name from source file (e.g., hello.py -> hello).
|
|
183
|
+
|
|
184
|
+
`extra_extensions` lets frontend-plugin source files (e.g. `.pas`)
|
|
185
|
+
contribute additional strippable suffixes.
|
|
186
|
+
"""
|
|
187
|
+
name = input_path.name
|
|
188
|
+
if name.endswith(".py"):
|
|
189
|
+
return name[:-3]
|
|
190
|
+
for ext in extra_extensions:
|
|
191
|
+
if name.endswith(ext):
|
|
192
|
+
return name[: -len(ext)]
|
|
193
|
+
return name
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _build_frontend_registry(plugin_specs: list[str],
|
|
197
|
+
dsl_opts: list[str]) -> FrontendRegistry | None:
|
|
198
|
+
"""Load plugins listed on the command line and return a registry.
|
|
199
|
+
|
|
200
|
+
Two-phase: resolve each plugin's class (so we learn its `name`
|
|
201
|
+
ClassVar without running `__init__`), route `--dsl-opt` values to
|
|
202
|
+
each plugin's options dict, *then* instantiate with the routed
|
|
203
|
+
dict. Plugins that validate required options in `__init__` see
|
|
204
|
+
the real values on the first call; reassigning `self.options`
|
|
205
|
+
after construction wouldn't trigger that path. Returns None when
|
|
206
|
+
no plugins were requested.
|
|
207
|
+
"""
|
|
208
|
+
if not plugin_specs:
|
|
209
|
+
if dsl_opts:
|
|
210
|
+
from .diagnostics import Diagnostic, DiagnosticLevel
|
|
211
|
+
raise FrontendPluginError(Diagnostic(
|
|
212
|
+
level=DiagnosticLevel.ERROR,
|
|
213
|
+
message=("--dsl-opt requires at least one --dsl-plugin"),
|
|
214
|
+
))
|
|
215
|
+
return None
|
|
216
|
+
plugin_classes = [resolve_plugin_class(spec) for spec in plugin_specs]
|
|
217
|
+
routed = route_dsl_opts(dsl_opts, [cls.name for cls in plugin_classes])
|
|
218
|
+
registry = FrontendRegistry()
|
|
219
|
+
for cls in plugin_classes:
|
|
220
|
+
registry.register(cls(routed.get(cls.name, {})))
|
|
221
|
+
return registry
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _split_tpyc_argv(argv: list[str]) -> tuple[list[str], list[str]]:
|
|
225
|
+
"""Split tpyc argv on the first `--` separator.
|
|
226
|
+
|
|
227
|
+
Returns (compiler_argv, script_args). Only the first `--` is honored; any
|
|
228
|
+
later `--` tokens are preserved as literal program args.
|
|
229
|
+
|
|
230
|
+
Raises ValueError if `--` is the first token (nothing for tpyc to parse).
|
|
231
|
+
"""
|
|
232
|
+
if "--" not in argv:
|
|
233
|
+
return argv, []
|
|
234
|
+
i = argv.index("--")
|
|
235
|
+
if i == 0 and argv[1:]:
|
|
236
|
+
raise ValueError("input file must appear before '--'")
|
|
237
|
+
return argv[:i], argv[i + 1:]
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _run_cli(is_runner: bool) -> int:
|
|
241
|
+
prog_name = "tpy" if is_runner else "tpyc"
|
|
242
|
+
parser = argparse.ArgumentParser(
|
|
243
|
+
prog=prog_name,
|
|
244
|
+
description=(
|
|
245
|
+
"TurboPython - run programs or start an interactive REPL"
|
|
246
|
+
if is_runner else
|
|
247
|
+
"TurboPython Compiler - compiles TurboPython to C++"
|
|
248
|
+
),
|
|
249
|
+
)
|
|
250
|
+
parser.add_argument("--version", action="version",
|
|
251
|
+
version=f"%(prog)s {__version__} ({get_git_commit()})")
|
|
252
|
+
parser.add_argument("input", nargs="?", help="Input TurboPython source file (.py)")
|
|
253
|
+
if is_runner:
|
|
254
|
+
# tpy: REMAINDER captures everything after the input positional, including
|
|
255
|
+
# flags like -O, matching `python script.py -O`. Limitation: flags that
|
|
256
|
+
# also exist as tpy options (e.g. -O) AND appear *before* the input
|
|
257
|
+
# positional are still consumed by tpy -- with `-c CMD`, there is no
|
|
258
|
+
# input positional to separate them. Use `--` to force forwarding:
|
|
259
|
+
# `tpy -c CMD -- -O arg`.
|
|
260
|
+
parser.add_argument("script_args", nargs=argparse.REMAINDER,
|
|
261
|
+
help="Arguments forwarded to the running program as sys.argv[1:]")
|
|
262
|
+
# tpyc: no REMAINDER positional -- tpyc's own options must be parseable in
|
|
263
|
+
# any position (including after the input file). Program args for --exec
|
|
264
|
+
# are pre-split off from argv on `--` before parse_args runs below.
|
|
265
|
+
parser.add_argument("-c", dest="cmd", metavar="CMD", help="Execute CMD as a TurboPython program string")
|
|
266
|
+
parser.add_argument("-o", "--output", help="Output directory (default: __tpyc__/ next to source)")
|
|
267
|
+
parser.add_argument("-v", "--verbose", action="count", default=0, help="Verbose output (-v commands+timing, -vv +generated C++)")
|
|
268
|
+
parser.add_argument("-b", "--build", action="store_true", help="Compile C++ to binary after generating")
|
|
269
|
+
parser.add_argument("-x", "--exec", action="store_true", help="Build and run the program")
|
|
270
|
+
parser.add_argument("-O", "--release", action="store_true", help="Build with optimizations (default: debug)")
|
|
271
|
+
parser.add_argument("--emit-source", action="store_true", help="Embed Python source as comments in generated C++")
|
|
272
|
+
parser.add_argument("-i", "--repl", action="store_true", help="Start interactive REPL")
|
|
273
|
+
parser.add_argument("--print-types", action="store_true", help="Print API reference (builtins, tplib, bundled stdlib) as markdown")
|
|
274
|
+
parser.add_argument("--install-agent-docs", metavar="DIR",
|
|
275
|
+
help="Install TPy agent docs (TPY_FOR_AGENTS.md, TPY_LANGUAGE_FEATURES.md, "
|
|
276
|
+
"TPY_STDLIB_ROADMAP.md, TPY_API_REFERENCE.md) into DIR and print "
|
|
277
|
+
"an AGENTS.md snippet to stdout")
|
|
278
|
+
parser.add_argument("--dump-code", action="store_true", help="Print generated C++ to stdout")
|
|
279
|
+
parser.add_argument(
|
|
280
|
+
"--default-int",
|
|
281
|
+
choices=DEFAULT_INT_CHOICES,
|
|
282
|
+
default="Int32",
|
|
283
|
+
help="Default type for unannotated integer literals (default: Int32)",
|
|
284
|
+
)
|
|
285
|
+
parser.add_argument(
|
|
286
|
+
"-L", "--lib", action="append", default=None,
|
|
287
|
+
help="Extra library search path (can be repeated)",
|
|
288
|
+
)
|
|
289
|
+
parser.add_argument(
|
|
290
|
+
"--no-stdlib", action="store_true",
|
|
291
|
+
help="Disable standard library (tplib, stdlib modules, tpy protocols)",
|
|
292
|
+
)
|
|
293
|
+
parser.add_argument(
|
|
294
|
+
"--cxx", default="auto",
|
|
295
|
+
help="C++ compiler: auto, list, gcc, gcc-14, clang, clang-18, zig, ... (default: auto)",
|
|
296
|
+
)
|
|
297
|
+
ccache_group = parser.add_mutually_exclusive_group()
|
|
298
|
+
ccache_group.add_argument("--ccache", action="store_true", default=None,
|
|
299
|
+
help="Force ccache usage")
|
|
300
|
+
ccache_group.add_argument("--no-ccache", dest="ccache", action="store_false",
|
|
301
|
+
help="Disable ccache")
|
|
302
|
+
parser.add_argument("--no-pch", dest="pch", action="store_false", default=True,
|
|
303
|
+
help="Disable precompiled header caching")
|
|
304
|
+
parser.add_argument("--no-bundle-runtime", dest="bundle_runtime",
|
|
305
|
+
action="store_false", default=True,
|
|
306
|
+
help="Don't copy runtime headers into the output directory")
|
|
307
|
+
parser.add_argument(
|
|
308
|
+
"--pcre2", choices=["bundled", "system", "auto", "none"], default="bundled",
|
|
309
|
+
help="PCRE2 source for the `re` module: bundled (vendored, default), "
|
|
310
|
+
"system (find_package / -lpcre2-8), auto (system, fall back to "
|
|
311
|
+
"bundled), or none (disabled -- any module that imports `re` "
|
|
312
|
+
"becomes a compile error, useful for embedded targets that want "
|
|
313
|
+
"to strip out regex)",
|
|
314
|
+
)
|
|
315
|
+
parser.add_argument(
|
|
316
|
+
"--dsl-plugin", action="append", default=None, metavar="SPEC",
|
|
317
|
+
help="Load a frontend plugin (path to .py file or importable module). "
|
|
318
|
+
"Can be repeated.",
|
|
319
|
+
)
|
|
320
|
+
parser.add_argument(
|
|
321
|
+
"--dsl-opt", action="append", default=None, metavar="NAME.KEY=VALUE",
|
|
322
|
+
help="Pass an option to a frontend plugin. Can be repeated.",
|
|
323
|
+
)
|
|
324
|
+
parser.add_argument("-j", "--jobs", type=int, default=None,
|
|
325
|
+
help="Parallel compile jobs (default: number of CPUs)")
|
|
326
|
+
parser.add_argument("--no-main", dest="no_main", action="store_true",
|
|
327
|
+
help="Skip main() generation (emit __tpy_main instead, for linking with external C++)")
|
|
328
|
+
parser.add_argument("-q", "--quiet", action="store_true",
|
|
329
|
+
help="Suppress progress lines (show only errors and program output)")
|
|
330
|
+
parser.add_argument("--info", action="store_true",
|
|
331
|
+
help="Print compiler version, paths, and environment info")
|
|
332
|
+
|
|
333
|
+
if is_runner:
|
|
334
|
+
args = parser.parse_args()
|
|
335
|
+
else:
|
|
336
|
+
# tpyc: program args (for --exec) must follow `--`, so tpyc's own
|
|
337
|
+
# options can appear anywhere -- including after the input file.
|
|
338
|
+
try:
|
|
339
|
+
tpyc_argv, script_args = _split_tpyc_argv(sys.argv[1:])
|
|
340
|
+
except ValueError as e:
|
|
341
|
+
parser.error(str(e))
|
|
342
|
+
args = parser.parse_args(tpyc_argv)
|
|
343
|
+
args.script_args = script_args
|
|
344
|
+
|
|
345
|
+
# tpy (runner) default action: bare `tpy` -> REPL; `tpy foo.py` -> run.
|
|
346
|
+
# Explicit actions (-b, -x, --dump-code, -i) and informational flags
|
|
347
|
+
# take precedence -- we only set a default when nothing else was requested.
|
|
348
|
+
# Piped stdin counts as input (matches `python < script.py`).
|
|
349
|
+
if is_runner:
|
|
350
|
+
has_input = bool(args.input or args.cmd) or not sys.stdin.isatty()
|
|
351
|
+
has_action = (
|
|
352
|
+
args.build or args.exec or args.dump_code or args.repl
|
|
353
|
+
or args.info or args.print_types
|
|
354
|
+
or args.install_agent_docs is not None
|
|
355
|
+
or args.cxx == "list"
|
|
356
|
+
)
|
|
357
|
+
if not has_action:
|
|
358
|
+
if has_input:
|
|
359
|
+
args.exec = True
|
|
360
|
+
else:
|
|
361
|
+
args.repl = True
|
|
362
|
+
|
|
363
|
+
# Build library search paths
|
|
364
|
+
lib_dir = get_lib_dir()
|
|
365
|
+
lib_dirs: list[Path] = []
|
|
366
|
+
for extra in (args.lib or []):
|
|
367
|
+
lib_dirs.append(Path(extra).resolve())
|
|
368
|
+
if not args.no_stdlib:
|
|
369
|
+
lib_dirs.append(lib_dir / "tpy")
|
|
370
|
+
|
|
371
|
+
# Handle --info
|
|
372
|
+
if args.info:
|
|
373
|
+
_print_info(prog_name)
|
|
374
|
+
return 0
|
|
375
|
+
|
|
376
|
+
# Handle --cxx list
|
|
377
|
+
if args.cxx == "list":
|
|
378
|
+
list_compilers()
|
|
379
|
+
return 0
|
|
380
|
+
|
|
381
|
+
# Handle REPL mode
|
|
382
|
+
if args.repl:
|
|
383
|
+
from .repl import REPLSession
|
|
384
|
+
preload_files = []
|
|
385
|
+
if args.input:
|
|
386
|
+
# Support multiple files separated by the input arg
|
|
387
|
+
preload_files = [Path(args.input).resolve()]
|
|
388
|
+
return REPLSession(verbose=args.verbose, preload_files=preload_files,
|
|
389
|
+
lib_dirs=lib_dirs, cxx=args.cxx).run()
|
|
390
|
+
|
|
391
|
+
# Handle --install-agent-docs (before --print-types so it's not silently dropped)
|
|
392
|
+
if args.install_agent_docs is not None:
|
|
393
|
+
from .install_docs import install_agent_docs, agents_md_snippet
|
|
394
|
+
target = Path(args.install_agent_docs).resolve()
|
|
395
|
+
try:
|
|
396
|
+
written = install_agent_docs(target)
|
|
397
|
+
except (NotADirectoryError, OSError) as e:
|
|
398
|
+
print(f"error: {e}", file=sys.stderr)
|
|
399
|
+
return 1
|
|
400
|
+
for p in written:
|
|
401
|
+
print(f"Wrote {p}", file=sys.stderr)
|
|
402
|
+
print(agents_md_snippet(Path(args.install_agent_docs)))
|
|
403
|
+
return 0
|
|
404
|
+
|
|
405
|
+
# Handle --print-types
|
|
406
|
+
if args.print_types:
|
|
407
|
+
from .dump_types import dump_builtin_types
|
|
408
|
+
dump_builtin_types()
|
|
409
|
+
return 0
|
|
410
|
+
|
|
411
|
+
# Handle -c: implies -x unless --dump-code or -b is set.
|
|
412
|
+
# With -c, a positional ends up in args.input due to nargs="?" -- prepend
|
|
413
|
+
# it to forwarded script args (matches `python -c CMD a b`). For tpyc,
|
|
414
|
+
# args.script_args may already contain tokens from a post-`--` separator;
|
|
415
|
+
# the input positional precedes them in sys.argv[1:] order.
|
|
416
|
+
if args.cmd is not None:
|
|
417
|
+
if args.input:
|
|
418
|
+
args.script_args = [args.input, *args.script_args]
|
|
419
|
+
args.input = None
|
|
420
|
+
if not args.dump_code and not args.build:
|
|
421
|
+
args.exec = True
|
|
422
|
+
|
|
423
|
+
# Auto-detect stdin when no input file given and stdin is piped/heredoc
|
|
424
|
+
if not args.cmd and not args.input and not sys.stdin.isatty():
|
|
425
|
+
args.input = "-"
|
|
426
|
+
|
|
427
|
+
# Require input file for non-REPL modes
|
|
428
|
+
if not args.cmd and not args.input:
|
|
429
|
+
parser.error("the following arguments are required: input (or -c CMD)")
|
|
430
|
+
|
|
431
|
+
# script_args only makes sense when the program is actually run.
|
|
432
|
+
# For tpy (runner), these come from REMAINDER after the input positional.
|
|
433
|
+
# For tpyc, they come either from after a `--` separator or from the -c
|
|
434
|
+
# shuffle above. In compile-only / --build / --dump-code modes, reject
|
|
435
|
+
# them with argparse's native "unrecognized arguments" phrasing.
|
|
436
|
+
if args.script_args and not args.exec:
|
|
437
|
+
parser.error(f"unrecognized arguments: {' '.join(args.script_args)}")
|
|
438
|
+
|
|
439
|
+
# Handle inline/stdin source
|
|
440
|
+
reading_from_stdin = args.cmd is not None or args.input == "-"
|
|
441
|
+
temp_dir = None
|
|
442
|
+
|
|
443
|
+
# Load frontend plugins, if any, before deriving the module name so
|
|
444
|
+
# that plugin-claimed extensions (e.g. `.pas`) are stripped.
|
|
445
|
+
try:
|
|
446
|
+
frontend_registry = _build_frontend_registry(
|
|
447
|
+
args.dsl_plugin or [], args.dsl_opt or [])
|
|
448
|
+
except FrontendPluginError as e:
|
|
449
|
+
print(f"error: {e.diagnostic.message}", file=sys.stderr)
|
|
450
|
+
return 1
|
|
451
|
+
plugin_extensions = (frontend_registry.all_extensions()
|
|
452
|
+
if frontend_registry is not None else frozenset())
|
|
453
|
+
# Plugins may contribute extra library search dirs (e.g. the
|
|
454
|
+
# Pascal frontend ships its stdlib at `pascal/lib/`). Append them
|
|
455
|
+
# before the implicit TPy stdlib so the user doesn't need a `-L`
|
|
456
|
+
# for each plugin-owned directory.
|
|
457
|
+
if frontend_registry is not None:
|
|
458
|
+
plugin_libs: list[Path] = []
|
|
459
|
+
for p in frontend_registry.plugins:
|
|
460
|
+
for d in p.library_paths():
|
|
461
|
+
plugin_libs.append(Path(d).resolve())
|
|
462
|
+
stdlib_pos = len(lib_dirs)
|
|
463
|
+
if not args.no_stdlib:
|
|
464
|
+
# `lib_dirs` ends with the TPy stdlib (`lib/tpy/`) when
|
|
465
|
+
# not --no-stdlib; keep plugin libs ahead of it so they
|
|
466
|
+
# don't shadow stdlib lookups but still come after user
|
|
467
|
+
# `-L` dirs.
|
|
468
|
+
stdlib_pos = len(lib_dirs) - 1
|
|
469
|
+
lib_dirs[stdlib_pos:stdlib_pos] = plugin_libs
|
|
470
|
+
|
|
471
|
+
if reading_from_stdin:
|
|
472
|
+
source = args.cmd if args.cmd is not None else sys.stdin.read()
|
|
473
|
+
module_name = "main"
|
|
474
|
+
temp_dir = tempfile.mkdtemp(prefix="tpyc_")
|
|
475
|
+
if args.output:
|
|
476
|
+
output_dir = Path(args.output)
|
|
477
|
+
else:
|
|
478
|
+
output_dir = Path(temp_dir)
|
|
479
|
+
input_path = None
|
|
480
|
+
else:
|
|
481
|
+
input_path = Path(args.input).resolve()
|
|
482
|
+
|
|
483
|
+
if not input_path.exists():
|
|
484
|
+
print(f"Error: Input file not found: {input_path}", file=sys.stderr)
|
|
485
|
+
return 1
|
|
486
|
+
|
|
487
|
+
# Determine output directory
|
|
488
|
+
if args.output:
|
|
489
|
+
output_dir = Path(args.output)
|
|
490
|
+
else:
|
|
491
|
+
# Default: __tpyc__/ next to source file
|
|
492
|
+
output_dir = input_path.parent / "__tpyc__"
|
|
493
|
+
|
|
494
|
+
# Get module name for output paths
|
|
495
|
+
module_name = get_module_name(input_path, plugin_extensions)
|
|
496
|
+
|
|
497
|
+
if args.dump_code and (args.build or args.exec):
|
|
498
|
+
parser.error("--dump-code cannot be combined with --build or --exec")
|
|
499
|
+
if args.jobs is not None and args.jobs < 1:
|
|
500
|
+
parser.error("-j/--jobs must be a positive integer")
|
|
501
|
+
building = args.build or args.exec
|
|
502
|
+
quiet = args.dump_code or args.quiet
|
|
503
|
+
explicit_output = bool(args.output)
|
|
504
|
+
n_jobs = args.jobs or os.cpu_count() or 1
|
|
505
|
+
progress = ProgressPrinter(enabled=not quiet)
|
|
506
|
+
|
|
507
|
+
try:
|
|
508
|
+
options = CodeGenOptions(emit_source_comments=args.emit_source,
|
|
509
|
+
no_main=args.no_main)
|
|
510
|
+
all_cpp_paths = []
|
|
511
|
+
|
|
512
|
+
cpp_config: CppCompilerConfig | None = None
|
|
513
|
+
if building:
|
|
514
|
+
cpp_config = CppCompilerConfig.from_env(cxx=args.cxx)
|
|
515
|
+
if args.ccache is not None:
|
|
516
|
+
cpp_config.ccache = args.ccache
|
|
517
|
+
progress.header(cpp_config, args.release, n_jobs)
|
|
518
|
+
else:
|
|
519
|
+
progress.header()
|
|
520
|
+
|
|
521
|
+
# Create compiler (unified for both stdin and file input)
|
|
522
|
+
t_compile_start = time.monotonic()
|
|
523
|
+
if reading_from_stdin:
|
|
524
|
+
compiler = Compiler.from_source(source, module_name, default_int=args.default_int,
|
|
525
|
+
lib_dirs=lib_dirs,
|
|
526
|
+
frontend_registry=frontend_registry)
|
|
527
|
+
else:
|
|
528
|
+
compiler = Compiler(input_path, default_int=args.default_int, lib_dirs=lib_dirs,
|
|
529
|
+
frontend_registry=frontend_registry)
|
|
530
|
+
|
|
531
|
+
compiled_modules = compiler.compile()
|
|
532
|
+
t_compile = time.monotonic() - t_compile_start
|
|
533
|
+
|
|
534
|
+
n_py = len(compiled_modules)
|
|
535
|
+
user_modules = [m.name for m in compiled_modules if compiler.is_user_module(m)]
|
|
536
|
+
n_stdlib = n_py - len(user_modules)
|
|
537
|
+
|
|
538
|
+
# Collect diagnostics: errors abort immediately, warnings are deferred
|
|
539
|
+
has_errors = False
|
|
540
|
+
warning_messages: list[str] = []
|
|
541
|
+
n_warnings = 0
|
|
542
|
+
for diag in compiler.diagnostics:
|
|
543
|
+
# Errors from the compiler driver itself (frontend plugin
|
|
544
|
+
# parse failures, module-resolution failures, etc.) must
|
|
545
|
+
# halt the build the same way analyzer-level errors do.
|
|
546
|
+
# Without this check a plugin's parse error surfaces as a
|
|
547
|
+
# downstream C++ compile failure because the empty-module
|
|
548
|
+
# fallback gets fed into the build pipeline.
|
|
549
|
+
if diag.level == DiagnosticLevel.ERROR:
|
|
550
|
+
has_errors = True
|
|
551
|
+
print(diag.format(prog_name), file=sys.stderr)
|
|
552
|
+
else:
|
|
553
|
+
n_warnings += 1
|
|
554
|
+
warning_messages.append(diag.format(prog_name))
|
|
555
|
+
for compiled in compiled_modules:
|
|
556
|
+
source_name = "<stdin>" if reading_from_stdin else os.path.relpath(compiled.path)
|
|
557
|
+
if compiled.analyzer:
|
|
558
|
+
for diag in compiled.analyzer.diagnostics:
|
|
559
|
+
if diag.level == DiagnosticLevel.ERROR:
|
|
560
|
+
has_errors = True
|
|
561
|
+
print(diag.format(source_name), file=sys.stderr)
|
|
562
|
+
elif diag.level == DiagnosticLevel.WARNING:
|
|
563
|
+
n_warnings += 1
|
|
564
|
+
warning_messages.append(diag.format(source_name))
|
|
565
|
+
|
|
566
|
+
progress.analyzed(user_modules, n_stdlib, n_warnings, t_compile)
|
|
567
|
+
|
|
568
|
+
if has_errors:
|
|
569
|
+
return 1
|
|
570
|
+
|
|
571
|
+
# Print warnings immediately when not building (no summary to defer to)
|
|
572
|
+
if not building:
|
|
573
|
+
for msg in warning_messages:
|
|
574
|
+
print(msg, file=sys.stderr)
|
|
575
|
+
|
|
576
|
+
t_codegen_start = time.monotonic()
|
|
577
|
+
for i, compiled in enumerate(compiled_modules, 1):
|
|
578
|
+
source_name = "<stdin>" if reading_from_stdin else os.path.relpath(compiled.path)
|
|
579
|
+
|
|
580
|
+
if args.dump_code:
|
|
581
|
+
try:
|
|
582
|
+
hpp_code, cpp_code = compiler.generate_code_to_strings(compiled, options=options)
|
|
583
|
+
except CodeGenError as e:
|
|
584
|
+
if e.filename is None and not compiled.is_entry_point:
|
|
585
|
+
e.filename = source_name
|
|
586
|
+
raise
|
|
587
|
+
if hpp_code:
|
|
588
|
+
print(f"// === include/{compiled.name}.hpp ===")
|
|
589
|
+
print(hpp_code)
|
|
590
|
+
if cpp_code:
|
|
591
|
+
print(f"// === src/{compiled.name}.cpp ===")
|
|
592
|
+
print(cpp_code)
|
|
593
|
+
continue
|
|
594
|
+
|
|
595
|
+
# -vv: show generated C++ inline
|
|
596
|
+
if args.verbose >= 2:
|
|
597
|
+
try:
|
|
598
|
+
hpp_code, cpp_code = compiler.generate_code_to_strings(compiled, options=options)
|
|
599
|
+
except CodeGenError as e:
|
|
600
|
+
if e.filename is None and not compiled.is_entry_point:
|
|
601
|
+
e.filename = source_name
|
|
602
|
+
raise
|
|
603
|
+
print(f"// === include/{compiled.name}.hpp ===")
|
|
604
|
+
print(hpp_code)
|
|
605
|
+
if cpp_code:
|
|
606
|
+
print(f"// === src/{compiled.name}.cpp ===")
|
|
607
|
+
print(cpp_code)
|
|
608
|
+
|
|
609
|
+
t_file_start = time.monotonic()
|
|
610
|
+
try:
|
|
611
|
+
hpp_path, cpp_path = compiler.generate_code(compiled, output_dir, options=options,
|
|
612
|
+
flat=explicit_output)
|
|
613
|
+
except CodeGenError as e:
|
|
614
|
+
if e.filename is None and not compiled.is_entry_point:
|
|
615
|
+
e.filename = source_name
|
|
616
|
+
raise
|
|
617
|
+
t_file = time.monotonic() - t_file_start
|
|
618
|
+
if cpp_path is not None:
|
|
619
|
+
all_cpp_paths.append(cpp_path)
|
|
620
|
+
progress.translated(compiled.name, t_file)
|
|
621
|
+
|
|
622
|
+
t_codegen = time.monotonic() - t_codegen_start
|
|
623
|
+
|
|
624
|
+
if args.dump_code:
|
|
625
|
+
return 0
|
|
626
|
+
|
|
627
|
+
n_cpp = len(all_cpp_paths)
|
|
628
|
+
|
|
629
|
+
# Generate sources.cmake for CMake integration
|
|
630
|
+
runtime_dir = get_runtime_dir()
|
|
631
|
+
link_flags = compiler.collect_link_flags()
|
|
632
|
+
|
|
633
|
+
# Resolve third-party deps (e.g. PCRE2 declared via
|
|
634
|
+
# `# tpy: link("pcre2", managed=True)`) into concrete build inputs.
|
|
635
|
+
# DisabledLibError is raised when the user passed `--<lib>=none` but
|
|
636
|
+
# a module in the compile graph needs that lib -- surface it as a
|
|
637
|
+
# clean compile error.
|
|
638
|
+
from .build.third_party import resolve_build_plan, DisabledLibError
|
|
639
|
+
third_party_modes = {"pcre2": args.pcre2}
|
|
640
|
+
try:
|
|
641
|
+
third_party_plan = resolve_build_plan(
|
|
642
|
+
dep_names=compiler.collect_third_party_deps(),
|
|
643
|
+
runtime_cpp_dir=runtime_dir / "cpp",
|
|
644
|
+
modes=third_party_modes,
|
|
645
|
+
)
|
|
646
|
+
except DisabledLibError as exc:
|
|
647
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
648
|
+
return 1
|
|
649
|
+
|
|
650
|
+
from .compiler import discover_runtime_cpp_sources
|
|
651
|
+
runtime_cpp_sources = discover_runtime_cpp_sources(runtime_dir / "cpp")
|
|
652
|
+
|
|
653
|
+
cmake_layout = BuildLayout(output_dir, module_name, flat=explicit_output)
|
|
654
|
+
cmake_layout.generate_cmake(
|
|
655
|
+
runtime_include_dir=runtime_dir / "cpp" / "include",
|
|
656
|
+
cpp_files=all_cpp_paths,
|
|
657
|
+
link_flags=link_flags,
|
|
658
|
+
bundle_runtime=args.bundle_runtime and not building and explicit_output,
|
|
659
|
+
third_party_libs=third_party_plan.libs,
|
|
660
|
+
runtime_cpp_sources=runtime_cpp_sources or None,
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
# Build if requested
|
|
664
|
+
if building:
|
|
665
|
+
assert cpp_config is not None
|
|
666
|
+
build_variant = "release" if args.release else "debug"
|
|
667
|
+
layout = BuildLayout(output_dir, module_name, build_variant=build_variant,
|
|
668
|
+
flat=explicit_output)
|
|
669
|
+
binary_path = layout.binary_path()
|
|
670
|
+
|
|
671
|
+
opt_flags = ["-O3", "-DNDEBUG"] if args.release else ["-g", "-O0"]
|
|
672
|
+
cpp_config.link_flags = link_flags
|
|
673
|
+
|
|
674
|
+
# Build or reuse precompiled header
|
|
675
|
+
pch_includes: list[Path] = []
|
|
676
|
+
if args.pch:
|
|
677
|
+
t_pch_start = time.monotonic()
|
|
678
|
+
pch_path = get_or_build_pch(
|
|
679
|
+
cpp_config, runtime_dir / "cpp" / "include", opt_flags,
|
|
680
|
+
pch_dir=layout.build_dir / "pch",
|
|
681
|
+
)
|
|
682
|
+
t_pch = time.monotonic() - t_pch_start
|
|
683
|
+
if pch_path:
|
|
684
|
+
pch_includes.append(pch_path)
|
|
685
|
+
progress.pch(t_pch)
|
|
686
|
+
# ccache needs these sloppiness flags for PCH support
|
|
687
|
+
if cpp_config.ccache:
|
|
688
|
+
slop = os.environ.get("CCACHE_SLOPPINESS", "")
|
|
689
|
+
parts = {s.strip() for s in slop.split(",") if s.strip()}
|
|
690
|
+
parts.update(("pch_defines", "time_macros"))
|
|
691
|
+
os.environ["CCACHE_SLOPPINESS"] = ",".join(sorted(parts))
|
|
692
|
+
|
|
693
|
+
compile_cmds = layout.build_cpp_commands(
|
|
694
|
+
runtime_include_dir=runtime_dir / "cpp" / "include",
|
|
695
|
+
cpp_files=all_cpp_paths,
|
|
696
|
+
opt_flags=opt_flags,
|
|
697
|
+
config=cpp_config,
|
|
698
|
+
force_includes=pch_includes or None,
|
|
699
|
+
extra_include_dirs=third_party_plan.extra_include_dirs or None,
|
|
700
|
+
extra_link_flags=third_party_plan.extra_link_flags or None,
|
|
701
|
+
c_sources=third_party_plan.c_sources or None,
|
|
702
|
+
runtime_cpp_sources=runtime_cpp_sources or None,
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
compile_steps = compile_cmds[:-1]
|
|
706
|
+
link_step = compile_cmds[-1]
|
|
707
|
+
|
|
708
|
+
t_build_start = time.monotonic()
|
|
709
|
+
|
|
710
|
+
def _cpp_name(cmd: list[str]) -> str:
|
|
711
|
+
"""Extract .cpp filename from a compile command."""
|
|
712
|
+
src = cmd[-1]
|
|
713
|
+
return os.path.basename(src)
|
|
714
|
+
|
|
715
|
+
# Compile steps in parallel (or serial for single file / -j1)
|
|
716
|
+
if len(compile_steps) <= 1 or n_jobs <= 1:
|
|
717
|
+
for cmd in compile_steps:
|
|
718
|
+
if args.verbose >= 1:
|
|
719
|
+
print(f" $ {' '.join(cmd)}", file=sys.stderr)
|
|
720
|
+
t_step = time.monotonic()
|
|
721
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
722
|
+
if result.returncode != 0:
|
|
723
|
+
print(f"C++ compilation failed:", file=sys.stderr)
|
|
724
|
+
print(result.stderr, file=sys.stderr)
|
|
725
|
+
return 1
|
|
726
|
+
progress.compiled(_cpp_name(cmd), time.monotonic() - t_step)
|
|
727
|
+
else:
|
|
728
|
+
if args.verbose >= 1:
|
|
729
|
+
for cmd in compile_steps:
|
|
730
|
+
print(f" $ {' '.join(cmd)}", file=sys.stderr)
|
|
731
|
+
failed_stderr = ""
|
|
732
|
+
with ThreadPoolExecutor(max_workers=n_jobs) as pool:
|
|
733
|
+
futures = {
|
|
734
|
+
pool.submit(_timed_run, cmd): cmd
|
|
735
|
+
for cmd in compile_steps
|
|
736
|
+
}
|
|
737
|
+
for future in as_completed(futures):
|
|
738
|
+
r, elapsed = future.result()
|
|
739
|
+
if r.returncode != 0 and not failed_stderr:
|
|
740
|
+
failed_stderr = r.stderr
|
|
741
|
+
else:
|
|
742
|
+
progress.compiled(_cpp_name(futures[future]), elapsed)
|
|
743
|
+
if failed_stderr:
|
|
744
|
+
print(f"C++ compilation failed:", file=sys.stderr)
|
|
745
|
+
print(failed_stderr, file=sys.stderr)
|
|
746
|
+
return 1
|
|
747
|
+
|
|
748
|
+
# Link step
|
|
749
|
+
if args.verbose >= 1:
|
|
750
|
+
print(f" $ {' '.join(link_step)}", file=sys.stderr)
|
|
751
|
+
t_link = time.monotonic()
|
|
752
|
+
result = subprocess.run(link_step, capture_output=True, text=True)
|
|
753
|
+
if result.returncode != 0:
|
|
754
|
+
print(f"C++ link failed:", file=sys.stderr)
|
|
755
|
+
print(result.stderr, file=sys.stderr)
|
|
756
|
+
return 1
|
|
757
|
+
progress.linked(module_name, time.monotonic() - t_link)
|
|
758
|
+
t_build = time.monotonic() - t_build_start
|
|
759
|
+
|
|
760
|
+
progress.summary(n_py, t_compile, t_codegen, t_build)
|
|
761
|
+
|
|
762
|
+
for msg in warning_messages:
|
|
763
|
+
print(msg, file=sys.stderr)
|
|
764
|
+
|
|
765
|
+
if not args.exec:
|
|
766
|
+
print(f"Built: {binary_path}")
|
|
767
|
+
|
|
768
|
+
# Run if requested
|
|
769
|
+
if args.exec:
|
|
770
|
+
progress.separator()
|
|
771
|
+
t_run_start = time.monotonic()
|
|
772
|
+
result = subprocess.run([str(binary_path), *args.script_args])
|
|
773
|
+
t_run = time.monotonic() - t_run_start
|
|
774
|
+
|
|
775
|
+
if args.verbose >= 1:
|
|
776
|
+
print(f" run: {t_run*1000:.0f}ms total: {(t_compile+t_codegen+t_build+t_run)*1000:.0f}ms",
|
|
777
|
+
file=sys.stderr)
|
|
778
|
+
|
|
779
|
+
return result.returncode
|
|
780
|
+
|
|
781
|
+
return 0
|
|
782
|
+
|
|
783
|
+
except CompilerNotFoundError as e:
|
|
784
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
785
|
+
return 1
|
|
786
|
+
except CompileError as e:
|
|
787
|
+
print(e.format(), file=sys.stderr)
|
|
788
|
+
return 1
|
|
789
|
+
except ParseError as e:
|
|
790
|
+
print(f"Parse error: {e}", file=sys.stderr)
|
|
791
|
+
return 1
|
|
792
|
+
except SemanticError as e:
|
|
793
|
+
error_filename = "<stdin>" if reading_from_stdin else input_path.name
|
|
794
|
+
print(e.format(error_filename), file=sys.stderr)
|
|
795
|
+
return 1
|
|
796
|
+
except CodeGenError as e:
|
|
797
|
+
error_filename = "<stdin>" if reading_from_stdin else input_path.name
|
|
798
|
+
print(e.format(error_filename), file=sys.stderr)
|
|
799
|
+
return 1
|
|
800
|
+
except FileNotFoundError as e:
|
|
801
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
802
|
+
return 1
|
|
803
|
+
except Exception as e:
|
|
804
|
+
print(f"Internal error: {e}", file=sys.stderr)
|
|
805
|
+
if args.verbose:
|
|
806
|
+
import traceback
|
|
807
|
+
traceback.print_exc()
|
|
808
|
+
return 1
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
def main_tpyc() -> int:
|
|
812
|
+
"""Entry point for the `tpyc` command (compiler mode)."""
|
|
813
|
+
return _run_cli(is_runner=False)
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
def main_tpy() -> int:
|
|
817
|
+
"""Entry point for the `tpy` command (runner mode)."""
|
|
818
|
+
return _run_cli(is_runner=True)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
if __name__ == "__main__":
|
|
822
|
+
sys.exit(main_tpyc())
|