hython-lang 2.0.0__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.
- hython/__init__.py +15 -0
- hython/__main__.py +3 -0
- hython/bytecode.py +368 -0
- hython/cli.py +449 -0
- hython/compiler.py +870 -0
- hython/compiler_manager.py +227 -0
- hython/diagnostics.py +158 -0
- hython/environment.py +48 -0
- hython/exe_builder.py +330 -0
- hython/frontend.py +870 -0
- hython/hir.py +93 -0
- hython/importer.py +76 -0
- hython/package_manager.py +343 -0
- hython/phonetics.py +49 -0
- hython/runtime.py +110 -0
- hython/runtime_manager.py +83 -0
- hython/translator.py +244 -0
- hython/updater.py +93 -0
- hython/vm.py +2409 -0
- hython/vocabulary.py +132 -0
- hython_lang-2.0.0.dist-info/METADATA +327 -0
- hython_lang-2.0.0.dist-info/RECORD +26 -0
- hython_lang-2.0.0.dist-info/WHEEL +5 -0
- hython_lang-2.0.0.dist-info/entry_points.txt +2 -0
- hython_lang-2.0.0.dist-info/licenses/LICENSE +22 -0
- hython_lang-2.0.0.dist-info/top_level.txt +1 -0
hython/cli.py
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
"""Command line interface for Hython."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import code
|
|
7
|
+
import platform
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from . import __version__
|
|
12
|
+
from .translator import audit_english, compile_hython, koreanize, to_hython, to_python
|
|
13
|
+
from .importer import install_importer
|
|
14
|
+
from .package_manager import (
|
|
15
|
+
infer_module_name, install as install_package, modules_for_distribution,
|
|
16
|
+
remove_dictionary,
|
|
17
|
+
scan as scan_package, uninstall as uninstall_package,
|
|
18
|
+
)
|
|
19
|
+
from .runtime import check_tree, inspect_runtime, sync_runtime
|
|
20
|
+
from .runtime_manager import (
|
|
21
|
+
install_runtime, list_runtimes, reexec_with_preferred_runtime,
|
|
22
|
+
run_hython_with_runtime, set_preference, RuntimeManagerError,
|
|
23
|
+
)
|
|
24
|
+
from .bytecode import read as read_hbc, write as write_hbc
|
|
25
|
+
from .compiler import compile_hir, compile_source
|
|
26
|
+
from .hir import format_hir
|
|
27
|
+
from .vm import VM
|
|
28
|
+
from .updater import initialize, refresh
|
|
29
|
+
from .compiler_manager import (
|
|
30
|
+
CompilerUpdateError, active_version as active_compiler_version,
|
|
31
|
+
check as check_compiler_update, reexec_with_active as reexec_with_active_compiler,
|
|
32
|
+
remove as remove_compiler, rollback as rollback_compiler,
|
|
33
|
+
update as update_compiler,
|
|
34
|
+
)
|
|
35
|
+
from .exe_builder import ExeBuildError, build_exe, create_archive, resolve_entry
|
|
36
|
+
from .environment import display_executable, external_source_root, is_frozen
|
|
37
|
+
|
|
38
|
+
COMMAND_ALIASES = {
|
|
39
|
+
"소스실행":"run", "모듈":"module", "변환":"translate", "감사":"audit",
|
|
40
|
+
"대화":"repl", "진단":"doctor", "초기화":"init", "업데이트":"update",
|
|
41
|
+
"컴파일러":"compiler", "패키지":"package", "런타임":"runtime",
|
|
42
|
+
"컴파일":"compile", "바이트실행":"execute", "실행파일":"exe",
|
|
43
|
+
"해체":"disassemble", "빌드":"build",
|
|
44
|
+
}
|
|
45
|
+
NESTED_ALIASES = {
|
|
46
|
+
"정보":"info", "확인":"check", "업데이트":"update",
|
|
47
|
+
"되돌리기":"rollback", "제거":"remove", "설치":"install",
|
|
48
|
+
"분석":"scan", "동기화":"sync", "검사":"check", "목록":"list",
|
|
49
|
+
"온라인":"online", "사용":"use",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _resource_argument(value: str) -> tuple[Path,Path]:
|
|
54
|
+
if "=" in value:
|
|
55
|
+
source,destination=value.split("=",1)
|
|
56
|
+
else:
|
|
57
|
+
source=value; destination=Path(value).name
|
|
58
|
+
if not source or not destination:
|
|
59
|
+
raise argparse.ArgumentTypeError("리소스 형식은 SOURCE 또는 SOURCE=DEST입니다.")
|
|
60
|
+
return Path(source),Path(destination)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _run(path: Path, args: list[str]) -> int:
|
|
64
|
+
source = path.read_text(encoding="utf-8")
|
|
65
|
+
namespace = {
|
|
66
|
+
"__name__": "__main__", "__file__": str(path),
|
|
67
|
+
"__package__": None, "__cached__": None,
|
|
68
|
+
}
|
|
69
|
+
old_argv = sys.argv
|
|
70
|
+
old_path = sys.path[:]
|
|
71
|
+
sys.argv = [str(path), *args]
|
|
72
|
+
sys.path.insert(0, str(path.resolve().parent))
|
|
73
|
+
install_importer()
|
|
74
|
+
try:
|
|
75
|
+
exec(compile_hython(source, str(path)), namespace)
|
|
76
|
+
finally:
|
|
77
|
+
sys.argv = old_argv
|
|
78
|
+
sys.path[:] = old_path
|
|
79
|
+
return 0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _repl() -> int:
|
|
83
|
+
banner = f"하이썬 {__version__} (Python {platform.python_version()})"
|
|
84
|
+
|
|
85
|
+
class Console(code.InteractiveConsole):
|
|
86
|
+
def runsource(self, source, filename="<하이썬>", symbol="single"):
|
|
87
|
+
return super().runsource(to_python(source), filename, symbol)
|
|
88
|
+
|
|
89
|
+
def showtraceback(self):
|
|
90
|
+
from .diagnostics import format_exception
|
|
91
|
+
error=sys.exception()
|
|
92
|
+
if error is not None:
|
|
93
|
+
print(format_exception(error),file=sys.stderr)
|
|
94
|
+
|
|
95
|
+
def showsyntaxerror(self, filename=None):
|
|
96
|
+
from .diagnostics import format_exception
|
|
97
|
+
error=sys.exception()
|
|
98
|
+
if error is not None:
|
|
99
|
+
print(format_exception(error,traceback_enabled=False),file=sys.stderr)
|
|
100
|
+
|
|
101
|
+
install_importer()
|
|
102
|
+
Console().interact(banner=banner, exitmsg="하이썬을 종료합니다.")
|
|
103
|
+
return 0
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
107
|
+
parser = argparse.ArgumentParser(prog="hython", description="발음으로 쓰는 한글 Python")
|
|
108
|
+
parser.add_argument("--version", action="version", version=f"하이썬 {__version__}")
|
|
109
|
+
sub = parser.add_subparsers(dest="command")
|
|
110
|
+
run = sub.add_parser("run", aliases=["소스실행"], help="하이썬 파일 실행")
|
|
111
|
+
run.add_argument("file", type=Path)
|
|
112
|
+
run.add_argument("args", nargs=argparse.REMAINDER)
|
|
113
|
+
module = sub.add_parser("module", aliases=["-m","모듈"], help="하이썬 모듈 실행")
|
|
114
|
+
module.add_argument("name")
|
|
115
|
+
module.add_argument("args", nargs=argparse.REMAINDER)
|
|
116
|
+
trans = sub.add_parser("translate", aliases=["변환"], help="소스 파일 변환")
|
|
117
|
+
trans.add_argument("file", type=Path)
|
|
118
|
+
trans.add_argument("--reverse", action="store_true", help="Python에서 하이썬으로 변환")
|
|
119
|
+
trans.add_argument("--complete", action="store_true", help="모든 영어 식별자를 발음형 한글로 변환")
|
|
120
|
+
trans.add_argument("-o", "--output", type=Path)
|
|
121
|
+
audit = sub.add_parser("audit", aliases=["감사"], help=".hy 소스에 남은 영어 식별자 검사")
|
|
122
|
+
audit.add_argument("path", nargs="?", type=Path, default=Path("."))
|
|
123
|
+
sub.add_parser("repl", aliases=["대화"], help="대화형 하이썬")
|
|
124
|
+
sub.add_parser("doctor", aliases=["진단"], help="실행 환경 확인")
|
|
125
|
+
init = sub.add_parser("init", aliases=["초기화"], help="최초 문법 환경 초기화")
|
|
126
|
+
init.add_argument("--force", action="store_true", help="현재 환경을 다시 생성")
|
|
127
|
+
update = sub.add_parser("update", aliases=["업데이트"], help="최신 Python 및 외부 문법 사전 갱신")
|
|
128
|
+
update.add_argument("--no-runtime", action="store_true", help="Python 다운로드 없이 현재 환경만 갱신")
|
|
129
|
+
update.add_argument("--activate-runtime", help=argparse.SUPPRESS)
|
|
130
|
+
compiler_update = sub.add_parser("compiler", aliases=["컴파일러"], help="외부 HBC 컴파일러 자동 업데이트 관리")
|
|
131
|
+
compiler_sub = compiler_update.add_subparsers(dest="compiler_command", required=True)
|
|
132
|
+
compiler_sub.add_parser("info", aliases=["정보"], help="현재 활성 컴파일러 확인")
|
|
133
|
+
compiler_sub.add_parser("check", aliases=["확인"], help="공식 최신 컴파일러 확인")
|
|
134
|
+
compiler_install = compiler_sub.add_parser("update", aliases=["업데이트"], help="최신 컴파일러 검증·설치·활성화")
|
|
135
|
+
compiler_install.add_argument("--force", action="store_true")
|
|
136
|
+
compiler_sub.add_parser("rollback", aliases=["되돌리기"], help="이전 검증 컴파일러로 복구")
|
|
137
|
+
compiler_remove = compiler_sub.add_parser("remove", aliases=["제거"], help="외부 컴파일러 삭제")
|
|
138
|
+
compiler_remove.add_argument("version", nargs="?")
|
|
139
|
+
package = sub.add_parser("package", aliases=["패키지"], help="Python 패키지 설치 및 발음 사전 관리")
|
|
140
|
+
package_sub = package.add_subparsers(dest="package_command", required=True)
|
|
141
|
+
package_install = package_sub.add_parser("install", aliases=["설치"], help="패키지를 설치하고 사전 생성")
|
|
142
|
+
package_install.add_argument("spec", help="pip 패키지 지정자")
|
|
143
|
+
package_install.add_argument("--module", help="import 모듈명 (패키지명과 다를 때)")
|
|
144
|
+
package_install.add_argument("--upgrade", action="store_true")
|
|
145
|
+
package_scan = package_sub.add_parser("scan", aliases=["분석"], help="설치된 모듈의 사전 생성")
|
|
146
|
+
package_scan.add_argument("module")
|
|
147
|
+
package_scan.add_argument("--static", action="store_true", help="모듈을 실행하지 않고 정적 분석만 사용")
|
|
148
|
+
package_uninstall = package_sub.add_parser("uninstall", aliases=["제거"], help="패키지와 생성된 사전 제거")
|
|
149
|
+
package_uninstall.add_argument("package", help="pip 배포 이름")
|
|
150
|
+
package_uninstall.add_argument("--module", help="삭제할 import 모듈명")
|
|
151
|
+
runtime = sub.add_parser("runtime", aliases=["런타임"], help="Python 런타임 분석 및 문법 호환성 검사")
|
|
152
|
+
runtime_sub = runtime.add_subparsers(dest="runtime_command", required=True)
|
|
153
|
+
runtime_sub.add_parser("info", aliases=["정보"], help="현재 Python 문법 정보")
|
|
154
|
+
runtime_sub.add_parser("sync", aliases=["동기화"], help="현재 Python 프로필 저장")
|
|
155
|
+
runtime_check = runtime_sub.add_parser("check", aliases=["검사"], help=".hy 파일 문법 검사")
|
|
156
|
+
runtime_check.add_argument("path", nargs="?", type=Path, default=Path("."))
|
|
157
|
+
runtime_sub.add_parser("list", aliases=["목록"], help="설치된 공식 Python 런타임 목록")
|
|
158
|
+
runtime_online = runtime_sub.add_parser("online", aliases=["온라인"], help="공식 온라인 런타임 검색")
|
|
159
|
+
runtime_online.add_argument("tag", nargs="?")
|
|
160
|
+
runtime_install = runtime_sub.add_parser("install", aliases=["설치"], help="공식 Python 런타임 설치")
|
|
161
|
+
runtime_install.add_argument("tag", nargs="?", default="default")
|
|
162
|
+
runtime_install.add_argument("--update", action="store_true")
|
|
163
|
+
runtime_install.add_argument("--dry-run", action="store_true")
|
|
164
|
+
runtime_use = runtime_sub.add_parser("use", aliases=["사용"], help="프로젝트 Python 런타임 지정")
|
|
165
|
+
runtime_use.add_argument("tag")
|
|
166
|
+
compile_cmd = sub.add_parser("compile", aliases=["컴파일"], help="하이썬 소스를 독립 HBC로 컴파일")
|
|
167
|
+
compile_cmd.add_argument("file", type=Path)
|
|
168
|
+
compile_cmd.add_argument("-o", "--output", type=Path)
|
|
169
|
+
compile_cmd.add_argument("--no-optimize", action="store_true")
|
|
170
|
+
compile_cmd.add_argument("--show-hir", action="store_true")
|
|
171
|
+
execute_cmd = sub.add_parser("execute", aliases=["바이트실행"], help="HBC를 하이썬 VM으로 실행")
|
|
172
|
+
execute_cmd.add_argument("file", type=Path)
|
|
173
|
+
exe_cmd = sub.add_parser("exe", aliases=["실행파일"], help="HBC를 독립 Windows EXE로 빌드")
|
|
174
|
+
exe_cmd.add_argument("file", type=Path, help="HBC 파일 또는 프로젝트 디렉터리")
|
|
175
|
+
exe_cmd.add_argument("--entry", help="프로젝트 entry HBC 상대 경로")
|
|
176
|
+
exe_cmd.add_argument("-o", "--output", type=Path)
|
|
177
|
+
exe_cmd.add_argument("--windowed", action="store_true", help="콘솔 창 없는 GUI 실행 파일")
|
|
178
|
+
exe_cmd.add_argument("--icon", type=Path, help="Windows .ico 파일")
|
|
179
|
+
exe_cmd.add_argument("--module-root", type=Path, help="함께 넣을 HBC 모듈 루트 (기본: 입력 폴더)")
|
|
180
|
+
exe_cmd.add_argument("--onedir", action="store_true", help="빠른 시작용 디렉터리 배포")
|
|
181
|
+
exe_cmd.add_argument("--resource", action="append", type=_resource_argument, default=[], metavar="SOURCE[=DEST]")
|
|
182
|
+
exe_cmd.add_argument("--exclude-module", action="append", default=[], help="사용하지 않는 Python 모듈 제외")
|
|
183
|
+
exe_cmd.add_argument("--product-name")
|
|
184
|
+
exe_cmd.add_argument("--file-version", default="1.0.0.0")
|
|
185
|
+
exe_cmd.add_argument("--company")
|
|
186
|
+
exe_cmd.add_argument("--description")
|
|
187
|
+
exe_cmd.add_argument("--copyright")
|
|
188
|
+
exe_cmd.add_argument("--sign-pfx", type=Path, help="Authenticode PFX 인증서")
|
|
189
|
+
exe_cmd.add_argument("--sign-password-env", help="PFX 암호가 든 환경 변수명")
|
|
190
|
+
exe_cmd.add_argument("--timestamp-url", default="http://timestamp.digicert.com")
|
|
191
|
+
exe_cmd.add_argument("--archive", type=Path, help="배포 ZIP과 .sha256 생성")
|
|
192
|
+
dis = sub.add_parser("disassemble", aliases=["해체"], help="HBC 명령어 표시")
|
|
193
|
+
dis.add_argument("file", type=Path)
|
|
194
|
+
build = sub.add_parser("build", aliases=["빌드"], help="하이썬 프로젝트를 HBC 디렉터리로 빌드")
|
|
195
|
+
build.add_argument("source", nargs="?", type=Path, default=Path("."))
|
|
196
|
+
build.add_argument("-o", "--output", type=Path, default=Path("dist"))
|
|
197
|
+
build.add_argument("--no-optimize", action="store_true")
|
|
198
|
+
return parser
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def main(argv: list[str] | None = None) -> int:
|
|
202
|
+
actual_argv = list(sys.argv[1:] if argv is None else argv)
|
|
203
|
+
reexec_with_active_compiler(actual_argv)
|
|
204
|
+
if not (actual_argv and actual_argv[0] == "runtime"):
|
|
205
|
+
start = Path(actual_argv[1]) if len(actual_argv) > 1 and actual_argv[0] == "run" else Path.cwd()
|
|
206
|
+
reexec_with_preferred_runtime(actual_argv, start)
|
|
207
|
+
parser = build_parser()
|
|
208
|
+
ns = parser.parse_args(actual_argv)
|
|
209
|
+
ns.command = COMMAND_ALIASES.get(ns.command,ns.command)
|
|
210
|
+
for attribute in ("compiler_command","package_command","runtime_command"):
|
|
211
|
+
if hasattr(ns,attribute):
|
|
212
|
+
value=getattr(ns,attribute)
|
|
213
|
+
setattr(ns,attribute,NESTED_ALIASES.get(value,value))
|
|
214
|
+
if ns.command != "init":
|
|
215
|
+
initialize()
|
|
216
|
+
if ns.command == "init":
|
|
217
|
+
result = initialize(force=ns.force)
|
|
218
|
+
if result["initialized"]:
|
|
219
|
+
print(f"하이썬 초기화 완료: {result['runtime']}")
|
|
220
|
+
else:
|
|
221
|
+
print("하이썬은 이미 초기화되어 있습니다.")
|
|
222
|
+
return 0
|
|
223
|
+
if ns.command == "update":
|
|
224
|
+
if not ns.no_runtime:
|
|
225
|
+
install_runtime("default", update=True)
|
|
226
|
+
result_code=run_hython_with_runtime("default",["update","--no-runtime","--activate-runtime","default"])
|
|
227
|
+
if result_code:
|
|
228
|
+
raise RuntimeManagerError(f"새 Python에서 문법 동기화 실패 (종료 코드 {result_code})")
|
|
229
|
+
print("최신 Python 런타임 설치 및 활성화 완료")
|
|
230
|
+
return 0
|
|
231
|
+
result = refresh(runtime_tag=getattr(ns,"activate_runtime",None))
|
|
232
|
+
print(f"문법 업데이트 완료: Python {platform.python_version()}")
|
|
233
|
+
print(f"패키지 사전: {len(result['refreshed'])}개 갱신, {len(result['removed'])}개 삭제")
|
|
234
|
+
return 0
|
|
235
|
+
if ns.command == "compiler":
|
|
236
|
+
if ns.compiler_command == "info":
|
|
237
|
+
active=active_compiler_version()
|
|
238
|
+
print(f"부트스트랩 컴파일러: {__version__}")
|
|
239
|
+
print(f"활성 외부 컴파일러: {active or '없음'}")
|
|
240
|
+
return 0
|
|
241
|
+
if ns.compiler_command == "check":
|
|
242
|
+
result=check_compiler_update()
|
|
243
|
+
print(f"현재: {result['current']}")
|
|
244
|
+
print(f"공식 최신: {result['version']}")
|
|
245
|
+
print(f"업데이트: {'가능' if result['update_available'] else '최신 상태'}")
|
|
246
|
+
return 0
|
|
247
|
+
if ns.compiler_command == "update":
|
|
248
|
+
result=update_compiler(force=ns.force)
|
|
249
|
+
if result["installed"]:
|
|
250
|
+
print(f"컴파일러 설치·검증·활성화 완료: {result['version']}")
|
|
251
|
+
print("다음 Hython 실행부터 새 컴파일러를 사용합니다.")
|
|
252
|
+
else:
|
|
253
|
+
print(f"컴파일러가 최신 상태입니다: {result['current']}")
|
|
254
|
+
return 0
|
|
255
|
+
if ns.compiler_command == "rollback":
|
|
256
|
+
version=rollback_compiler()
|
|
257
|
+
print(f"컴파일러 복구 완료: {version or '내장 부트스트랩'}")
|
|
258
|
+
return 0
|
|
259
|
+
version=remove_compiler(ns.version)
|
|
260
|
+
print(f"외부 컴파일러 삭제 완료: {version}")
|
|
261
|
+
return 0
|
|
262
|
+
if ns.command == "run":
|
|
263
|
+
return _run(ns.file, ns.args)
|
|
264
|
+
if ns.command == "compile":
|
|
265
|
+
output = ns.output or ns.file.with_suffix(".hbc")
|
|
266
|
+
output.parent.mkdir(parents=True,exist_ok=True)
|
|
267
|
+
source = ns.file.read_text(encoding="utf-8-sig")
|
|
268
|
+
hir = compile_hir(source, str(ns.file), optimize=not ns.no_optimize)
|
|
269
|
+
if ns.show_hir:
|
|
270
|
+
print(format_hir(hir))
|
|
271
|
+
write_hbc(output, compile_source(source, str(ns.file), optimize=not ns.no_optimize))
|
|
272
|
+
print(f"HBC 생성: {output}")
|
|
273
|
+
return 0
|
|
274
|
+
if ns.command == "execute":
|
|
275
|
+
VM([ns.file.resolve().parent]).run(read_hbc(ns.file))
|
|
276
|
+
return 0
|
|
277
|
+
if ns.command == "exe":
|
|
278
|
+
entry,project_root=resolve_entry(ns.file,ns.entry)
|
|
279
|
+
if ns.output:
|
|
280
|
+
output=ns.output
|
|
281
|
+
elif ns.onedir:
|
|
282
|
+
output=(ns.file if ns.file.is_dir() else ns.file.parent)/(entry.stem+"-dist")
|
|
283
|
+
else:
|
|
284
|
+
output=entry.with_suffix(".exe")
|
|
285
|
+
metadata={
|
|
286
|
+
"version":ns.file_version,"name":entry.stem,
|
|
287
|
+
**({"product":ns.product_name} if ns.product_name else {}),
|
|
288
|
+
**({"company":ns.company} if ns.company else {}),
|
|
289
|
+
**({"description":ns.description} if ns.description else {}),
|
|
290
|
+
**({"copyright":ns.copyright} if ns.copyright else {}),
|
|
291
|
+
}
|
|
292
|
+
result=build_exe(
|
|
293
|
+
entry,output,console=not ns.windowed,icon=ns.icon,
|
|
294
|
+
module_root=ns.module_root or project_root,resources=ns.resource,
|
|
295
|
+
onefile=not ns.onedir,metadata=metadata,excludes=set(ns.exclude_module),
|
|
296
|
+
sign_pfx=ns.sign_pfx,sign_password_env=ns.sign_password_env,
|
|
297
|
+
timestamp_url=ns.timestamp_url,
|
|
298
|
+
)
|
|
299
|
+
print(f"EXE 생성: {result}")
|
|
300
|
+
if ns.archive:
|
|
301
|
+
archive,checksum=create_archive(result,ns.archive)
|
|
302
|
+
print(f"배포 압축: {archive}")
|
|
303
|
+
print(f"SHA-256: {checksum}")
|
|
304
|
+
return 0
|
|
305
|
+
if ns.command == "disassemble":
|
|
306
|
+
code = read_hbc(ns.file)
|
|
307
|
+
for index, instruction in enumerate(code.instructions):
|
|
308
|
+
print(f"{index:04d} {instruction[0]:14} {' '.join(map(str, instruction[1:]))}")
|
|
309
|
+
return 0
|
|
310
|
+
if ns.command == "build":
|
|
311
|
+
source_root=ns.source.resolve()
|
|
312
|
+
files=[source_root] if source_root.is_file() else sorted(source_root.rglob("*.hy"))
|
|
313
|
+
if not files:
|
|
314
|
+
parser.error(f".hy 파일을 찾을 수 없습니다: {ns.source}")
|
|
315
|
+
for source_file in files:
|
|
316
|
+
relative=Path(source_file.name) if source_root.is_file() else source_file.relative_to(source_root)
|
|
317
|
+
output=(ns.output/relative).with_suffix(".hbc")
|
|
318
|
+
output.parent.mkdir(parents=True,exist_ok=True)
|
|
319
|
+
code=compile_source(source_file.read_text(encoding="utf-8-sig"),str(relative),optimize=not ns.no_optimize)
|
|
320
|
+
write_hbc(output,code)
|
|
321
|
+
print(f"빌드: {relative} -> {output}")
|
|
322
|
+
print(f"빌드 완료: {len(files)}개 모듈")
|
|
323
|
+
return 0
|
|
324
|
+
if ns.command in ("module", "-m"):
|
|
325
|
+
install_importer()
|
|
326
|
+
old_argv = sys.argv
|
|
327
|
+
sys.argv = [ns.name, *ns.args]
|
|
328
|
+
try:
|
|
329
|
+
import runpy
|
|
330
|
+
runpy.run_module(ns.name, run_name="__main__", alter_sys=True)
|
|
331
|
+
finally:
|
|
332
|
+
sys.argv = old_argv
|
|
333
|
+
return 0
|
|
334
|
+
if ns.command == "translate":
|
|
335
|
+
source = ns.file.read_text(encoding="utf-8")
|
|
336
|
+
if ns.complete:
|
|
337
|
+
if not ns.reverse:
|
|
338
|
+
parser.error("--complete는 Python을 하이썬으로 바꾸는 --reverse와 함께 사용하세요.")
|
|
339
|
+
result = koreanize(source)
|
|
340
|
+
else:
|
|
341
|
+
result = to_hython(source) if ns.reverse else to_python(source)
|
|
342
|
+
if ns.output:
|
|
343
|
+
ns.output.write_text(result, encoding="utf-8")
|
|
344
|
+
else:
|
|
345
|
+
print(result, end="")
|
|
346
|
+
return 0
|
|
347
|
+
if ns.command == "audit":
|
|
348
|
+
paths=[ns.path] if ns.path.is_file() else sorted(ns.path.rglob("*.hy"))
|
|
349
|
+
found=0
|
|
350
|
+
for path in paths:
|
|
351
|
+
for item in audit_english(path.read_text(encoding="utf-8-sig")):
|
|
352
|
+
print(f"{path}:{item.line}:{item.column}: {item.name} -> {item.suggestion}")
|
|
353
|
+
found+=1
|
|
354
|
+
if found:
|
|
355
|
+
print(f"영어 식별자 {found}개 발견",file=sys.stderr)
|
|
356
|
+
return 1
|
|
357
|
+
print(f"완전 한글 문법 검사 통과: {ns.path}")
|
|
358
|
+
return 0
|
|
359
|
+
if ns.command == "doctor":
|
|
360
|
+
print(f"하이썬: {__version__}\nPython: {platform.python_version()}\n실행 파일: {display_executable()}")
|
|
361
|
+
if is_frozen():
|
|
362
|
+
source=external_source_root()
|
|
363
|
+
print(f"업데이트용 번들 소스: {source} ({'정상' if (source/'hython'/'cli.py').is_file() else '누락'})")
|
|
364
|
+
return 0
|
|
365
|
+
if ns.command == "package":
|
|
366
|
+
if ns.package_command == "install":
|
|
367
|
+
module = ns.module or infer_module_name(ns.spec)
|
|
368
|
+
install_package(ns.spec, upgrade=ns.upgrade)
|
|
369
|
+
for discovered in modules_for_distribution(ns.spec,ns.module):
|
|
370
|
+
output = scan_package(discovered, deep=True)
|
|
371
|
+
print(f"전체 공개 API 발음 사전 생성: {output}")
|
|
372
|
+
return 0
|
|
373
|
+
if ns.package_command == "uninstall":
|
|
374
|
+
module = ns.module or infer_module_name(ns.package)
|
|
375
|
+
modules = modules_for_distribution(ns.package,ns.module)
|
|
376
|
+
uninstall_package(ns.package)
|
|
377
|
+
removed = [name for name in modules if remove_dictionary(name)]
|
|
378
|
+
print(f"패키지 제거 완료: {ns.package}")
|
|
379
|
+
print(f"발음 사전 삭제: {len(removed)}개 ({', '.join(removed) or '대상 없음'})")
|
|
380
|
+
return 0
|
|
381
|
+
output = scan_package(ns.module, deep=not ns.static)
|
|
382
|
+
print(f"발음 사전 생성: {output}")
|
|
383
|
+
return 0
|
|
384
|
+
if ns.command == "runtime":
|
|
385
|
+
if ns.runtime_command == "info":
|
|
386
|
+
info = inspect_runtime()
|
|
387
|
+
print(f"Python: {info['version']} ({info['implementation']})")
|
|
388
|
+
print(f"실행 파일: {info['executable']}")
|
|
389
|
+
print(f"키워드: {len(info['hard_keywords'])}개")
|
|
390
|
+
print(f"소프트 키워드: {', '.join(info['soft_keywords']) or '없음'}")
|
|
391
|
+
print(f"미등록 새 키워드: {', '.join(info['new_keywords']) or '없음'}")
|
|
392
|
+
return 0
|
|
393
|
+
if ns.runtime_command == "sync":
|
|
394
|
+
print(f"런타임 프로필 생성: {sync_runtime()}")
|
|
395
|
+
return 0
|
|
396
|
+
if ns.runtime_command == "list":
|
|
397
|
+
print(list_runtimes(), end="")
|
|
398
|
+
return 0
|
|
399
|
+
if ns.runtime_command == "online":
|
|
400
|
+
print(list_runtimes(online=True, tag=ns.tag), end="")
|
|
401
|
+
return 0
|
|
402
|
+
if ns.runtime_command == "install":
|
|
403
|
+
install_runtime(ns.tag, update=ns.update, dry_run=ns.dry_run)
|
|
404
|
+
if not ns.dry_run:
|
|
405
|
+
print(f"Python 런타임 설치 완료: {ns.tag}")
|
|
406
|
+
return 0
|
|
407
|
+
if ns.runtime_command == "use":
|
|
408
|
+
print(f"프로젝트 런타임 지정: {set_preference(Path.cwd(), ns.tag)}")
|
|
409
|
+
print(f"설치 전 확인: hython runtime install {ns.tag} --dry-run")
|
|
410
|
+
return 0
|
|
411
|
+
failures = check_tree(ns.path)
|
|
412
|
+
if failures:
|
|
413
|
+
for path, error in failures:
|
|
414
|
+
print(f"실패: {path}\n {error}", file=sys.stderr)
|
|
415
|
+
return 1
|
|
416
|
+
print(f"문법 검사 통과: {ns.path}")
|
|
417
|
+
return 0
|
|
418
|
+
if ns.command in (None, "repl"):
|
|
419
|
+
return _repl()
|
|
420
|
+
parser.error("알 수 없는 명령입니다.")
|
|
421
|
+
return 2
|
|
422
|
+
|
|
423
|
+
def entrypoint() -> int:
|
|
424
|
+
"""Console entry point with stable, user-facing diagnostics."""
|
|
425
|
+
from .bytecode import BytecodeError
|
|
426
|
+
from .compiler import CompileError
|
|
427
|
+
from .frontend import ParseError
|
|
428
|
+
from .runtime_manager import RuntimeManagerError
|
|
429
|
+
from .vm import VMError
|
|
430
|
+
try:
|
|
431
|
+
return main()
|
|
432
|
+
except KeyboardInterrupt:
|
|
433
|
+
print("하이썬: 사용자가 실행을 중단했습니다.",file=sys.stderr)
|
|
434
|
+
return 1
|
|
435
|
+
except SystemExit:
|
|
436
|
+
raise
|
|
437
|
+
except BaseException as exc:
|
|
438
|
+
import os,traceback
|
|
439
|
+
if os.environ.get("HYTHON_TRACEBACK","").lower()=="python":
|
|
440
|
+
traceback.print_exception(exc)
|
|
441
|
+
else:
|
|
442
|
+
from .diagnostics import format_exception
|
|
443
|
+
expected=isinstance(exc,(ParseError,CompileError,BytecodeError,VMError,RuntimeManagerError,CompilerUpdateError,ExeBuildError))
|
|
444
|
+
print(format_exception(exc,traceback_enabled=not expected),file=sys.stderr)
|
|
445
|
+
return 1
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
if __name__ == "__main__":
|
|
449
|
+
raise SystemExit(entrypoint())
|