codecin 5.6.0__tar.gz → 5.8.0__tar.gz
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.
- {codecin-5.6.0 → codecin-5.8.0}/CHANGELOG.md +255 -2
- {codecin-5.6.0/codecin.egg-info → codecin-5.8.0}/PKG-INFO +10 -10
- {codecin-5.6.0 → codecin-5.8.0}/README.md +9 -9
- {codecin-5.6.0 → codecin-5.8.0}/codecin/__init__.py +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/codecin/aot.py +185 -4
- {codecin-5.6.0 → codecin-5.8.0}/codecin/cin.py +687 -47
- {codecin-5.6.0 → codecin-5.8.0}/codecin/cli.py +40 -5
- {codecin-5.6.0 → codecin-5.8.0}/codecin/config.py +4 -2
- {codecin-5.6.0 → codecin-5.8.0}/codecin/cpu.py +12 -7
- {codecin-5.6.0 → codecin-5.8.0}/codecin/disasm.py +2 -2
- codecin-5.8.0/codecin/environment.py +176 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/isa.py +24 -0
- codecin-5.8.0/codecin/lib/bigint.cin +589 -0
- codecin-5.8.0/codecin/lib/bitset.cin +374 -0
- codecin-5.8.0/codecin/lib/codec.cin +563 -0
- codecin-5.8.0/codecin/lib/combin.cin +414 -0
- codecin-5.8.0/codecin/lib/cppstd.cin +418 -0
- codecin-5.8.0/codecin/lib/cstd.cin +424 -0
- codecin-5.8.0/codecin/lib/csv.cin +405 -0
- codecin-5.8.0/codecin/lib/dp.cin +325 -0
- codecin-5.8.0/codecin/lib/fmt.cin +325 -0
- codecin-5.8.0/codecin/lib/frac.cin +252 -0
- codecin-5.8.0/codecin/lib/gostd.cin +406 -0
- codecin-5.8.0/codecin/lib/graph.cin +367 -0
- codecin-5.8.0/codecin/lib/gui.cin +206 -0
- codecin-5.8.0/codecin/lib/heap.cin +199 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/key.cin +26 -2
- codecin-5.8.0/codecin/lib/path.cin +372 -0
- codecin-5.8.0/codecin/lib/set.cin +269 -0
- codecin-5.8.0/codecin/lib/text.cin +323 -0
- codecin-5.8.0/codecin/lib/token.cin +183 -0
- codecin-5.8.0/codecin/lib/tree.cin +256 -0
- codecin-5.8.0/codecin/lib/unionfind.cin +115 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/memory.py +17 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/aot/aot.go +4 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/codegen.go +26 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/syscalls.go +18 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/tokenizer.go +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/types.go +0 -1
- codecin-5.8.0/codecin/native/engine/args.go +37 -0
- codecin-5.8.0/codecin/native/engine/audio.go +402 -0
- codecin-5.8.0/codecin/native/engine/audio_other.go +105 -0
- codecin-5.8.0/codecin/native/engine/audio_test.go +279 -0
- codecin-5.8.0/codecin/native/engine/audio_windows.go +190 -0
- codecin-5.8.0/codecin/native/engine/console_other.go +9 -0
- codecin-5.8.0/codecin/native/engine/console_windows.go +43 -0
- codecin-5.8.0/codecin/native/engine/gui.go +178 -0
- codecin-5.8.0/codecin/native/engine/gui_stub.go +11 -0
- codecin-5.8.0/codecin/native/engine/gui_test.go +148 -0
- codecin-5.8.0/codecin/native/engine/gui_windows.go +426 -0
- codecin-5.8.0/codecin/native/engine/gui_x11.go +721 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/isa_gen.go +18 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard.go +165 -11
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard_other.go +3 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard_stub.go +3 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard_test.go +53 -26
- codecin-5.8.0/codecin/native/engine/keyboard_windows.go +196 -0
- codecin-5.8.0/codecin/native/engine/keyboard_windows_test.go +97 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/mem_other.go +0 -2
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/mem_windows.go +0 -2
- codecin-5.8.0/codecin/native/engine/stdin.go +66 -0
- codecin-5.8.0/codecin/native/engine/stdin_other.go +9 -0
- codecin-5.8.0/codecin/native/engine/stdin_windows.go +60 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/system.go +0 -3
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/version_gen.go +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/vm.go +92 -35
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/main.go +21 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native.py +17 -1
- codecin-5.8.0/codecin/stdlib.py +123 -0
- codecin-5.8.0/codecin/version.py +274 -0
- {codecin-5.6.0 → codecin-5.8.0/codecin.egg-info}/PKG-INFO +10 -10
- {codecin-5.6.0 → codecin-5.8.0}/codecin.egg-info/SOURCES.txt +68 -0
- codecin-5.8.0/examples/args_demo.cin +22 -0
- {codecin-5.6.0 → codecin-5.8.0}/examples/asm_constants.asm +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/examples/bitwise_builtins.cin +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/examples/control_flow.cin +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/examples/enum_range_for.cin +1 -1
- codecin-5.8.0/examples/gui_demo.cin +49 -0
- {codecin-5.6.0 → codecin-5.8.0}/examples/literals_types.cin +1 -1
- codecin-5.8.0/examples/local_audio.cin +58 -0
- {codecin-5.6.0 → codecin-5.8.0}/examples/modules_demo.cin +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/examples/stdlib_demo.cin +1 -1
- {codecin-5.6.0 → codecin-5.8.0}/examples/system_interaction.cin +1 -1
- codecin-5.8.0/misc/vscode-cin/.vscodeignore +4 -0
- codecin-5.8.0/misc/vscode-cin/README.md +34 -0
- codecin-5.8.0/misc/vscode-cin/build.bat +3 -0
- codecin-5.8.0/misc/vscode-cin/language-configuration.json +87 -0
- codecin-5.8.0/misc/vscode-cin/package.json +52 -0
- codecin-5.8.0/misc/vscode-cin/snippets/cin.json +113 -0
- codecin-5.8.0/misc/vscode-cin/syntaxes/cin.tmLanguage.json +254 -0
- {codecin-5.6.0 → codecin-5.8.0}/pyproject.toml +3 -0
- codecin-5.8.0/script/bump_version.py +349 -0
- {codecin-5.6.0 → codecin-5.8.0}/setup.py +11 -1
- codecin-5.8.0/tests/test_aggregate_and_const.py +377 -0
- codecin-5.8.0/tests/test_all_libs_together.py +107 -0
- codecin-5.8.0/tests/test_aot.py +433 -0
- codecin-5.8.0/tests/test_cin_host.py +133 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cli.py +14 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_compiler_errors.py +8 -7
- codecin-5.8.0/tests/test_environment.py +57 -0
- codecin-5.8.0/tests/test_gui.py +177 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_keyboard.py +8 -4
- codecin-5.8.0/tests/test_lib_bigint.py +322 -0
- codecin-5.8.0/tests/test_lib_bitset.py +472 -0
- codecin-5.8.0/tests/test_lib_codec.py +164 -0
- codecin-5.8.0/tests/test_lib_combin.py +276 -0
- codecin-5.8.0/tests/test_lib_compat.py +532 -0
- codecin-5.8.0/tests/test_lib_csv.py +241 -0
- codecin-5.8.0/tests/test_lib_dp.py +256 -0
- codecin-5.8.0/tests/test_lib_fmt.py +230 -0
- codecin-5.8.0/tests/test_lib_frac.py +201 -0
- codecin-5.8.0/tests/test_lib_graph.py +353 -0
- codecin-5.8.0/tests/test_lib_heap.py +234 -0
- codecin-5.8.0/tests/test_lib_path.py +250 -0
- codecin-5.8.0/tests/test_lib_set.py +294 -0
- codecin-5.8.0/tests/test_lib_text.py +246 -0
- codecin-5.8.0/tests/test_lib_token.py +158 -0
- codecin-5.8.0/tests/test_lib_tree.py +130 -0
- codecin-5.8.0/tests/test_lib_unionfind.py +150 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_p0_fixes.py +14 -8
- codecin-5.8.0/tests/test_struct_value_semantics.py +440 -0
- codecin-5.8.0/tests/test_version.py +424 -0
- codecin-5.6.0/codecin/lib/gui.cin +0 -94
- codecin-5.6.0/codecin/native/engine/audio.go +0 -152
- codecin-5.6.0/codecin/native/engine/audio_other.go +0 -46
- codecin-5.6.0/codecin/native/engine/audio_windows.go +0 -43
- codecin-5.6.0/codecin/native/engine/keyboard_windows.go +0 -70
- codecin-5.6.0/tests/test_aot.py +0 -206
- codecin-5.6.0/tests/test_cin_host.py +0 -59
- codecin-5.6.0/tests/test_version.py +0 -58
- {codecin-5.6.0 → codecin-5.8.0}/LICENSE +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/MANIFEST.in +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/assembler.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/cache.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/console.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/crom.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/debugger.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/errors.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/jit.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/array.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/bits.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/conv.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/hash.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/io.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/json.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/math.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/matrix.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/queue.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/rand.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/sort.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/stat.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/str.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/termux.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/test.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/time.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/validate.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/lib/vec.cin +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/logger.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/aot/stub_main.go.txt +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/build.ps1 +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/build.sh +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/compile_test.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/compiler/parser.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/canvas.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/crom.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/encode.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/engine_test.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/host_test.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/hostcrypto.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/hostdesktop.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/hostnet.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard_termios_darwin.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/keyboard_termios_linux.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/engine/termux.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/go.mod +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/native/ir/ir.go +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/registers.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin/stats.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin.egg-info/dependency_links.txt +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin.egg-info/entry_points.txt +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin.egg-info/requires.txt +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/codecin.egg-info/top_level.txt +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/misc/vim/ftdetect/codecin.vim +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/misc/vim/syntax/cin.vim +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/misc/vim/syntax/codecinasm.vim +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/script/check_paths.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/script/gen_isa_docs.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/script/gen_native_isa.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/setup.cfg +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_assembler_ext.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cache.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cin_host_ext.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cin_new_features.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cin_syntax.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cin_syntax_ext.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cin_system.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_cpu_interpreted.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_debugger.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_examples.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_ab.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_crom_mmu.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_import.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_importloc.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_mmu.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_features_remote.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_index_subscript_type.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_isa_dispatch.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_isa_single_source.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_libs.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_libs_ext.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_literals_and_bom.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_memory_protection.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_native_hardening.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_native_lib_lookup.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_nested_subscript_codegen.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_no_go_cli.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_packaging.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_paths_consistency.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_switch_semantics.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_three_paths.py +0 -0
- {codecin-5.6.0 → codecin-5.8.0}/tests/test_workflows.py +0 -0
|
@@ -5,6 +5,259 @@
|
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## [5.8.0] - 2026-10-04
|
|
9
|
+
|
|
10
|
+
一次「图形、媒体与跨平台兼容」发布:新增 **GUI 窗口**(Windows Win32 /
|
|
11
|
+
Linux X11)、**本地音频扩展**(真实音量 / 播放进度 / 合成蜂鸣)、**键盘输入
|
|
12
|
+
多平台优化**(Unicode 码点、F11/F12、修饰键组合),并补齐 **命令行参数与
|
|
13
|
+
行输入**(SYS 129..131)、**终端输出缓存的跨平台冲刷**(Windows VT/UTF-8
|
|
14
|
+
初始化)与 **C/C++/Go 三语言标准库兼容层**(36 → 39 个)。随后在同一版本内
|
|
15
|
+
继续增强:**音频控制全家桶**(查询 / 暂停恢复 / 音量读取,SYS 132..136)、
|
|
16
|
+
**三兼容层 API 扩容**(40+ 新函数)、**工具链缺失检测与平台化安装提示**
|
|
17
|
+
(environment)与 **`--libs` 内置库清单**(标注执行路径要求)。核心实现全部
|
|
18
|
+
在 Go 原生引擎(纯标准库,零第三方依赖),三条执行路径语义与 5.7.x 保持一致。
|
|
19
|
+
|
|
20
|
+
### 新增 (Added)
|
|
21
|
+
|
|
22
|
+
#### GUI 窗口(SYS 119..125、128,全部 Go 原生实现)
|
|
23
|
+
|
|
24
|
+
- **`gui_new(w, h, title)` / `gui_update()` / `gui_close()` / `gui_closed()` /
|
|
25
|
+
`gui_active()` / `mouse_x()` / `mouse_y()` / `mouse_button()`**:
|
|
26
|
+
- `gui_new` 成功返回 0 并把画布内建(`set_color` / `fill_rect` / `fill_circle` /
|
|
27
|
+
`draw_line` / `draw_text`)直接绑定为**窗口后备缓冲直画**,`gui_update`
|
|
28
|
+
处理事件并呈现一帧(主循环每帧调用);`gui_close` 销毁窗口(画布保留,
|
|
29
|
+
仍可 `save_png`);点 X / Alt+F4 / WM 删除协议由 `gui_closed` 报告。
|
|
30
|
+
- 平台后端:Windows 用 Win32(专用窗口线程 + 消息泵,`StretchDIBits`
|
|
31
|
+
呈现,`AdjustWindowRect` 精确客户区);Linux 用**纯 Go X11 客户端**
|
|
32
|
+
(Unix socket / TCP 连接、MIT-MAGIC-COOKIE-1 认证、`PutImage` 分块呈现、
|
|
33
|
+
WM_DELETE_WINDOW 协议);其他平台与无显示服务环境一律优雅失败
|
|
34
|
+
(`gui_new` 返回 -1,不报错不崩溃)。
|
|
35
|
+
- 鼠标:客户区坐标 + 键位掩码(bit0 左 / bit1 右 / bit2 中);键盘事件注入
|
|
36
|
+
与终端共用的同一键码队列(`get_key` 可直接读)。
|
|
37
|
+
- 并发安全:快照复制防撕裂(呈现线程读 / VM 线程写)。
|
|
38
|
+
- **`codecin/lib/gui.cin` 重构**:窗口封装 `g_new` / `g_update` / `g_close` /
|
|
39
|
+
`g_closed` / `g_active` / `g_clear` / `g_mouse_*`(含键位判定),并**保留**
|
|
40
|
+
5.7.x 的离屏绘图助手(`g_rgb` / `g_bar_chart` / `g_line_chart` / `g_grid` /
|
|
41
|
+
`g_rect_outline` / `g_save` / `g_show`)。
|
|
42
|
+
|
|
43
|
+
#### 本地音频扩展(SYS 126、127)
|
|
44
|
+
|
|
45
|
+
- **`audio_pos()`**:当前播放已进行毫秒;无播放 / 已播完 / 时长未知返回 -1。
|
|
46
|
+
- **`beep(freq, ms)`**:合成 16-bit 单声道 22050Hz 正弦蜂鸣(10% / 5ms 淡入
|
|
47
|
+
淡出防爆音);频率 20..20000 Hz、单次上限 10 秒,参数校验在三平台一致地
|
|
48
|
+
于触碰设备之前完成。
|
|
49
|
+
- Windows 后端从 PlaySoundW 升级为 **waveOut 流式**:`audio_volume` 经
|
|
50
|
+
`waveOutSetVolume` 实时生效、`audio_stop` 即时中止(`waveOutReset`);
|
|
51
|
+
Unix 后端向 `paplay` / `ffplay` / `afplay` 透传音量参数。
|
|
52
|
+
|
|
53
|
+
#### 音频控制增强(SYS 132..136)
|
|
54
|
+
|
|
55
|
+
- **`audio_duration()`**:当前播放总时长毫秒;无播放 / 自然播完 / 时长未知返回 -1
|
|
56
|
+
(播放与暂停期间返回同一总时长)。
|
|
57
|
+
- **`audio_playing()`**:1 = 正在发声(已开始、未暂停、未播完),否则 0。
|
|
58
|
+
- **`audio_pause()`**:暂停当前播放(Windows `waveOutPause`;Unix 向播放器
|
|
59
|
+
进程投递 SIGSTOP),成功 0;无播放 / 已暂停 / 平台失败为 -1。
|
|
60
|
+
- **`audio_resume()`**:恢复暂停的播放,时间基线整体后移暂停时长——
|
|
61
|
+
`audio_pos` 无缝续走、自然结束时刻保持正确;成功 0 / 无暂停可恢复 -1。
|
|
62
|
+
- **`audio_level()`**:读取当前音量 0..100(`audio_volume` 的读端)。
|
|
63
|
+
- **`audio_pos` 暂停冻结**:暂停期间进度停在暂停时刻,不随真实时间前进;
|
|
64
|
+
`audio_stop` / 重新播放即解除暂停态。
|
|
65
|
+
- 五个内建在两侧编译器同步登记,ISA 真源(`isa.py`)→ Go 生成物一致。
|
|
66
|
+
|
|
67
|
+
#### 键盘输入多平台优化(键码表扩展)
|
|
68
|
+
|
|
69
|
+
- 新增键码:**F11 / F12**(1031 / 1032)、**Ctrl+方向**(1101..1104)、
|
|
70
|
+
**Shift+方向**(1105..1108)、**Shift+Tab**(1109)。
|
|
71
|
+
- **XTerm 修饰参数解析**:`CSI 1;5C`(Ctrl+Right)等修饰变体三端一致。
|
|
72
|
+
- **Unicode 码点解码**(Linux / macOS / Termux):终端 UTF-8 多字节序列解码为
|
|
73
|
+
码点(>255,如 "中" → 0x4E2D),非法序列回退按字节处理;Windows 端
|
|
74
|
+
UTF-16 代理对组合为同一码点。
|
|
75
|
+
- **Windows 输入重写**:msvcrt `_getch` → `ReadConsoleInputW` 事件流
|
|
76
|
+
(UTF-16 字符 + VK 虚拟键,键抬起过滤、重复计数、扩展键),启用时关闭
|
|
77
|
+
QuickEdit 防误选卡死。
|
|
78
|
+
- `codecin/lib/key.cin`:`K_F11` / `K_F12` / `K_CTRL_*` / `K_SHIFT_*` /
|
|
79
|
+
`K_SHIFT_TAB` 常量与 `k_is_function` / `k_is_modified_arrow` 判定;
|
|
80
|
+
`k_is_special` 范围同步扩展。
|
|
81
|
+
|
|
82
|
+
#### 命令行参数与行输入(SYS 129..131,跨平台一致语义)
|
|
83
|
+
|
|
84
|
+
- **`arg_count()` / `arg(i)`**:读取传给 CIN 程序的命令行参数(不含程序文件名;
|
|
85
|
+
越界 / 负下标返回空串)。传参约定三端统一:
|
|
86
|
+
- CLI:`codecin prog.cin -- a b c`(`--` 之后的参数全部交给 CIN 程序);
|
|
87
|
+
- AOT 产物:直接取进程 `os.Args[1:]`;
|
|
88
|
+
- c-shared 库:新导出 `codecin_set_args`,Python 桥接层每次运行前注入
|
|
89
|
+
(空列表即清空,同进程多次运行不残留)。
|
|
90
|
+
- **`input_str()`**:读入一行 UTF-8 文本(不含行尾;EOF 为空串)。优先消费
|
|
91
|
+
预读输入缓冲(与解释器 `input()` 的管道语义一致),耗尽后阻塞读标准输入;
|
|
92
|
+
Windows 控制台用 `ReadConsoleW`(UTF-16 → UTF-8,中文输入不乱码),其余平台
|
|
93
|
+
用 `bufio` 按行读;行尾 `\n` / `\r\n` 三平台统一剥离,与键盘 raw 模式
|
|
94
|
+
(监听激活时临时恢复行模式)互不干扰。
|
|
95
|
+
- 新内建在两侧编译器同步登记(`arg_count` / `arg` / `input_str`)。
|
|
96
|
+
|
|
97
|
+
#### 终端输出缓存与 Windows 控制台兼容
|
|
98
|
+
|
|
99
|
+
- **阻塞读前冲刷输出缓冲**:原生引擎把输出缓冲到程序结束一次性回传;
|
|
100
|
+
当 `input_str()` / 数字输入将要阻塞读真实终端时先冲刷已缓冲输出,
|
|
101
|
+
`"你的名字: "` 这类交互提示立即可见。冲刷**仅在 stdout 为终端时生效**——
|
|
102
|
+
管道 / 重定向 / 测试捕获下输出字节序列与旧版本完全一致。
|
|
103
|
+
- **Windows 控制台一次性初始化**(进程级、幂等、失败安全):
|
|
104
|
+
`ENABLE_VIRTUAL_TERMINAL_PROCESSING`(ANSI/VT 转义序列在传统 conhost 上
|
|
105
|
+
与 Linux/macOS 行为一致)+ `SetConsoleOutputCP(65001)`(输出代码页切
|
|
106
|
+
UTF-8,中文 Windows 默认 GBK 下中文/Emoji 不再乱码)。
|
|
107
|
+
- AOT 产物在打印输出前执行同一初始化;非 Windows 平台为空操作
|
|
108
|
+
(终端原生支持 VT 与 UTF-8)。
|
|
109
|
+
|
|
110
|
+
#### C / C++ / Go 标准库兼容层(36 → 39 个,全部纯 CIN)
|
|
111
|
+
|
|
112
|
+
- **`codecin/lib/cstd.cin`(`libc_*`)**:`<ctype.h>`(isdigit / toupper …,
|
|
113
|
+
字符码可用字符字面量 `'A'` 直接传入)、`<string.h>`(strlen / strcmp /
|
|
114
|
+
strstr / strchr / strrev / memcpy …)、`<stdlib.h>`(abs / atoi / qsort_asc)、
|
|
115
|
+
`<math.h>`(fabs / sqrt / pow / floor / ceil / fmod 商向零截断)与
|
|
116
|
+
`<stdio.h>`(puts / print)。
|
|
117
|
+
- **`codecin/lib/cppstd.cin`(`stl_*`)**:`std::string`(find / rfind /
|
|
118
|
+
substr / append / to_string,npos 以 -1 表示)、`vector<int>` / `stack<int>` /
|
|
119
|
+
`queue<int>`(**数组 + 长度游标**表达,push/pop 返回新长度)、
|
|
120
|
+
`<utility>`(max / min / abs / swap / sort 固定升序)。
|
|
121
|
+
- **`codecin/lib/gostd.cin`(`go_*`)**:`strings`(Contains / Index /
|
|
122
|
+
HasPrefix / Repeat / Count / ReplaceAll / EqualFold …)、`strconv`(Itoa /
|
|
123
|
+
Atoi / FormatFloat)、`math`、`slices`(Index / Contains / Max / Reverse …)
|
|
124
|
+
与 `os.Args`(经 `go_os_args_len` / `go_os_args_get`,依赖原生路径)。
|
|
125
|
+
- 类型映射约定:C `char*` → `string`、C `char` → 字符码 `int`、C 数组参数 →
|
|
126
|
+
CIN 数组引用 + 显式长度;与 C/C++ 指针返回值不可表达的 API(如返回
|
|
127
|
+
`char*` 的 strchr)以**下标**语义对齐,头注释均注明差异。
|
|
128
|
+
|
|
129
|
+
#### 兼容层 API 扩容(三库 40+ 新函数,纯 CIN、三路径一致)
|
|
130
|
+
|
|
131
|
+
- **cstd**:`<ctype.h>` 补 iscntrl / isgraph / isblank / ispunct / toascii;
|
|
132
|
+
`<string.h>` 补 memmove / strspn / strcspn / strpbrk / strlwr / strupr;
|
|
133
|
+
`<stdlib.h>` 补 labs / rand / srand;`<math.h>` 补 sin / cos / tan /
|
|
134
|
+
round(C 语义半值远离零)/ trunc;`<stdio.h>` 补 putchar(配套内部
|
|
135
|
+
字符码 → 字符串转换)。
|
|
136
|
+
- **cppstd**:`std::string` 补 starts_with / ends_with(C++20)/
|
|
137
|
+
find_first_of / find_last_of / at / front / back / insert / erase /
|
|
138
|
+
replace;`vector<int>` 补 find / count / insert / erase;`<algorithm>`
|
|
139
|
+
补 sort 降序版与 clamp。
|
|
140
|
+
- **gostd**:`strings` 补 LastIndex / IndexAny / TrimLeft / TrimRight /
|
|
141
|
+
TrimPrefix / TrimSuffix;`strconv` 补 FormatInt(base 2..36)/
|
|
142
|
+
ParseInt(任意进制解析);`math` 补 Round / Trunc;`slices` 补
|
|
143
|
+
LastIndex / Equal / Clone / Sort。
|
|
144
|
+
|
|
145
|
+
#### 工具链缺失检测与平台化安装提示(environment)
|
|
146
|
+
|
|
147
|
+
- **`codecin/environment.py`**:`find_tool` / `tool_available`(只读
|
|
148
|
+
`shutil.which` 探测,绝不自动安装)、`install_hint`(按当前平台给出可复制
|
|
149
|
+
执行的安装命令:Windows winget/MSYS2、macOS brew/xcode-select、Linux
|
|
150
|
+
apt/dnf/pacman、Termux pkg)、`missing_tool_message`(缺工具 + 用途 +
|
|
151
|
+
怎么装合一)、`native_runtime_hint`(原生库缺失时的三条出路指引)。
|
|
152
|
+
- 接入点(所有缺失入口提示一致):
|
|
153
|
+
- AOT 构建缺 Go:报错附 `install_hint('go')`(原先只有干巴巴的
|
|
154
|
+
"go 命令未找到");
|
|
155
|
+
- 解释路径(含 `--no-native`)调用宿主能力内建:报错附原生库安装指引;
|
|
156
|
+
- pip 安装(`setup.py`)缺 Go:打印安装命令并说明重装后获得原生加速。
|
|
157
|
+
|
|
158
|
+
#### `--libs`:内置标准库清单与执行路径标注
|
|
159
|
+
|
|
160
|
+
- 新 CLI 选项 **`--libs`**:列出 `codecin/lib/` 全部官方库并按**执行路径
|
|
161
|
+
要求**标注三类——纯 CIN(三路径一致)/ 兼容层(C/C++/Go 三语言标准库
|
|
162
|
+
兼容层)/ 需原生运行时(调用宿主能力内建,`--no-native` 与沙箱下不可用)。
|
|
163
|
+
- 分类由**源码扫描**得出(是否引用 `HOST_BUILTINS` 内建名),与库头注释
|
|
164
|
+
保持单一事实来源;`gostd.cin` 的 `go_os_args_*` 原生依赖自动标注。
|
|
165
|
+
|
|
166
|
+
#### 其他
|
|
167
|
+
|
|
168
|
+
- 新内建在两侧编译器同步登记:Python `HOST_BUILTINS` 与 Go
|
|
169
|
+
`compiler.hostBuiltins`(并补上 5.6.0 遗漏的 `key_hit` / `get_key` /
|
|
170
|
+
`key_flush`)。
|
|
171
|
+
- 新示例:`examples/gui_demo.cin`(无显示服务自动降级为提示后退出)、
|
|
172
|
+
`examples/local_audio.cin`、`examples/args_demo.cin`(`--` 传参与
|
|
173
|
+
`input_str`)。
|
|
174
|
+
- 新测试:`tests/test_lib_compat.py`(三兼容层函数语义、参数注入管道、
|
|
175
|
+
预读缓冲行输入、无原生库可编译,解释 / 原生双路径参数化)。
|
|
176
|
+
- 本轮新增:Go 侧 `engine/audio_test.go`(audio_duration / playing /
|
|
177
|
+
pause / resume 状态机、暂停冻结、自然播完回落)、`tests/test_environment.py`
|
|
178
|
+
(安装提示契约)、`tests/test_cli.py::test_list_libs_reports_categories`
|
|
179
|
+
(--libs 分类标注);`examples/local_audio.cin` 增补音量读取与暂停 /
|
|
180
|
+
恢复演示。
|
|
181
|
+
|
|
182
|
+
### 变更 (Changed)
|
|
183
|
+
|
|
184
|
+
- **`lib/gui.cin` 签名变更**(窗口化重构):`g_new(w, h)` → `g_new(w, h, title)`
|
|
185
|
+
(旧的无窗口画布用法请直接使用 `canvas(w, h)`);`g_clear(w, h, rgb)` →
|
|
186
|
+
`g_clear(rgb)`(沿用最近一次窗口尺寸,从未开窗时返回 -1)。
|
|
187
|
+
图表助手内部已同步适配,`g_bar_chart` / `g_line_chart` / `g_save` /
|
|
188
|
+
`g_show` 调用方式不变。
|
|
189
|
+
|
|
190
|
+
### 修复 (Fixed)
|
|
191
|
+
|
|
192
|
+
- 音频自然播完后 `audio_pos` 不再恒返回总时长(正确恢复 -1)。
|
|
193
|
+
- GUI:Windows 窗口线程改为常驻,`gui_close` 之后可以再次 `gui_new`;
|
|
194
|
+
窗口销毁(无论来自 `gui_close` 还是用户点 X)后清理失效句柄。
|
|
195
|
+
- `guiSnapshot` 增加窗口打开校验(关闭后不再产出快照)。
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## [5.7.4] - 2026-09-28
|
|
200
|
+
|
|
201
|
+
一次「静默错误清零 + 标准库扩容」的发布:修掉一族会**静默破坏内存/静默给错结果**的
|
|
202
|
+
struct 缺陷与两处**同一程序两条路径结论不同**的分歧,并把官方标准库从 20 个扩到 36 个。
|
|
203
|
+
|
|
204
|
+
### 新增 (Added)
|
|
205
|
+
|
|
206
|
+
- **标准库 20 → 36 个**(全部为纯 CIN,只调用语言内建,三条执行路径一致):
|
|
207
|
+
- 数据结构与算法:`tree.cin`(`tree_`)、`unionfind.cin`(`uf_`)、`heap.cin`(`heap_`)、
|
|
208
|
+
`graph.cin`(`graph_`)、`dp.cin`(`dp_`)、`set.cin`(`set_`)、`bitset.cin`(`bs_`)
|
|
209
|
+
- 文本与格式化:`text.cin`(`txt_`)、`token.cin`(`tok_`)、`fmt.cin`(`fmt_`)、`csv.cin`(`csv_`)
|
|
210
|
+
- 数值与科学计算:`bigint.cin`(`bi_`,任意精度)、`frac.cin`(`fr_`,有理数)、
|
|
211
|
+
`combin.cin`(`comb_`,数论与组合)
|
|
212
|
+
- 工程与系统:`path.cin`(`path_`,纯字符串路径)、`codec.cin`(`codec_`,十六进制/URL/
|
|
213
|
+
Base64/RLE/摩尔斯/XOR)
|
|
214
|
+
- **`const` 命名常量**:`const int N = 4`(全局与局部),支持 `int/float/bool/string`,
|
|
215
|
+
纯编译期、不占数据段,可用于**数组维度**与任意表达式;可被同名局部变量遮蔽。
|
|
216
|
+
- **数组维度接受整型常量表达式**:`int a[N]`、`int a[2 + 3]`、`int a[enumMember + 1]`。
|
|
217
|
+
- **struct 聚合初始化**:`P p = {3, 4}`、`P ps[2] = {{1,2},{3,4}}`、嵌套 `Out o = {{5,6},7}`;
|
|
218
|
+
未列出的字段取默认值,初始化器过多是编译期错误。
|
|
219
|
+
- **`string +=`**:右侧任意可字符串化的值。
|
|
220
|
+
- **`exit(code)`**:立即结束程序,三条路径与 AOT 产物一致。
|
|
221
|
+
- **版本设施**:`codecin/version.py`(`version_info()` / `compare()` / `build_info()` 等,
|
|
222
|
+
`build_info()` 永不抛异常)、CLI 新增 `--build-info` 与 `--build-info --json`、
|
|
223
|
+
`script/bump_version.py`(改真源 → 重生成 Go 版本常量 → 插 CHANGELOG 骨架,含回滚与 `--dry-run`)。
|
|
224
|
+
|
|
225
|
+
### 修复 (Fixed)
|
|
226
|
+
|
|
227
|
+
- **struct 聚合初始化写穿指针槽**:`P p = {3, 4}` 会把第 2 个字面量写到 `FP + 0`,
|
|
228
|
+
**覆盖保存的帧指针**;全局 `P o = {3,4}` 覆盖对象指针。现按字段写入堆对象。
|
|
229
|
+
- **struct 数组成员访问写到绝对地址 0 / 8**:元素槽被当成指针解引用,
|
|
230
|
+
`ps[0].y = 1` 会**静默破坏数据段**(字符串字面量所在处)。现统一为
|
|
231
|
+
「槽里存对象指针」模型,每个元素各有对象。
|
|
232
|
+
- **初始化器过多时两条路径结论不同**:解释器越界写后返回残值、原生 VM 抛
|
|
233
|
+
`Address out of bounds`。现为编译期错误 `Too many initializers for struct P`。
|
|
234
|
+
- **struct 整体赋值是指针别名**:`P b = a; b.x = 7` 会改到 `a.x`,与文档承诺的
|
|
235
|
+
「值拷贝」不符。现按槽逐字拷贝(**传参仍保持文档规定的「引用可见」**)。
|
|
236
|
+
- **嵌套 struct 字段只按 1 槽推进**:`struct Out { In i; int c }` 的 `c` 压在 `i.b` 上;
|
|
237
|
+
且成员取值会把内嵌字段当指针解引用。两处均已修正。
|
|
238
|
+
- **`parse_array_literal` 静默丢弃尾部平铺元素**:`{{5, 6}, 7}` 里的 `7` 消失。
|
|
239
|
+
- **字符串字节语义分歧**:解释器侧 `+` / `substr` / `indexof` 先做 UTF-8 解码,
|
|
240
|
+
非法字节序列被替换成 U+FFFD,实测 `strlen(substr("中",2,1)+substr("中",1,1))`
|
|
241
|
+
解释器 9 / 原生 3。现全部改为字节级。
|
|
242
|
+
- **用户函数与内建同名时永远不会被调用**:`--no-native` 报宿主能力错误、原生路径
|
|
243
|
+
静默走宿主实现(两条路径结论不同)。现用户函数优先于同名内建。
|
|
244
|
+
- **局部 struct 字段默认值**:`MALLOC` 并不清零,此前「全零」只是堆恰好干净;
|
|
245
|
+
现于函数序言显式清零。
|
|
246
|
+
- **AOT 临时目录**:清理失败不再静默(记 warning 并给出残留绝对路径与手动删除命令);
|
|
247
|
+
每次构建前清扫超过 6 小时的 `.aotbuild-*` / `.aotprobe-*`;
|
|
248
|
+
新增 `[tool.setuptools.exclude-package-data]` 使残留不再进 wheel。
|
|
249
|
+
|
|
250
|
+
### 变更 (Changed)
|
|
251
|
+
|
|
252
|
+
- **无法自洽的 struct 写法改为编译期报错**(原先静默算错):多维 struct 数组
|
|
253
|
+
`P ps[2][3]`、struct 数组字段 `struct Bag { P items[3] }`、跨 struct 类型赋值
|
|
254
|
+
`P p; Q q; p = q;`、把 struct 写进标量槽 `int a[2]; a[0] = p;`。
|
|
255
|
+
- `tests/test_keyboard.py`、`tests/test_p0_fixes.py` 由 `tmp_path` 改用 `workdir` 夹具,
|
|
256
|
+
受限沙箱下不再出现 5 个 setup 阶段 `ERROR`。
|
|
257
|
+
- 新增跨库集成护栏 `tests/test_all_libs_together.py`:31 个纯 CIN 库同时 import 并各调用一个接口。
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
8
261
|
## [5.6.0] - 2026-09-27
|
|
9
262
|
|
|
10
263
|
一次以「静默错误清零 + 安全加固」为主的修复发布,落地 `docs/SUGGESTIONS_NEXT.md`
|
|
@@ -254,7 +507,7 @@
|
|
|
254
507
|
|
|
255
508
|
### 修复 (Fixed)
|
|
256
509
|
|
|
257
|
-
- `
|
|
510
|
+
- `codecin --help` 的首行版本号长期停留在 `Code CIN v5.3`,现直接取
|
|
258
511
|
`codecin.__version__`(此前是全仓唯一残留的版本串)。
|
|
259
512
|
- `--build-exe` 在程序文件不存在时抛裸 `FileNotFoundError` traceback,现在与普通路径
|
|
260
513
|
一样给出 `Build Error` 面板。
|
|
@@ -305,7 +558,7 @@
|
|
|
305
558
|
### 新增 (Added)
|
|
306
559
|
|
|
307
560
|
- **AOT 静态编译: 编译成独立可执行文件 (Windows / Linux / macOS)**:
|
|
308
|
-
`
|
|
561
|
+
`codecin program.cin --build-exe app` 或 `codecin build program.cin -o app`,
|
|
309
562
|
支持 `--target OS/ARCH` 交叉编译(windows/amd64|arm64、linux/amd64|arm64、darwin/amd64|arm64)。
|
|
310
563
|
产物内嵌 UCBC 字节码与初始内存镜像,由内置 Go VM 执行,**不依赖 Python、Go 工具链、
|
|
311
564
|
libc 或任何动态库**(`CGO_ENABLED=0`,Linux 产物无 `PT_INTERP`);入口 shell 模板由
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecin
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.8.0
|
|
4
4
|
Summary: Code CIN - 高级语言与运行时 (CIN/PL/ASM 工具链 + Go 原生 VM + ARM64/RISC-V/FP/Vector 指令集)
|
|
5
5
|
Author: ByUsi Studio, 北啊呢
|
|
6
6
|
License-Expression: MIT
|
|
@@ -443,9 +443,9 @@ codecin --version
|
|
|
443
443
|
|
|
444
444
|
3. 运行:
|
|
445
445
|
```
|
|
446
|
-
|
|
446
|
+
codecin basic.cin # 唯一 CLI 入口 (自动用 Go 原生库)
|
|
447
447
|
codecin basic.cin # 安装后等价的 console script
|
|
448
|
-
|
|
448
|
+
codecin --help
|
|
449
449
|
```
|
|
450
450
|
|
|
451
451
|
> **Python 只是 CLI 外壳**: 语言实现 (`codecin/native/` 下的 Go 编译器与字节码 VM) 全部在 Go 侧,
|
|
@@ -485,11 +485,11 @@ ruff check codecin cpu.py script tests
|
|
|
485
485
|
|
|
486
486
|
```bash
|
|
487
487
|
# 本机平台
|
|
488
|
-
|
|
488
|
+
codecin program.cin --build-exe program # Windows 自动补 .exe
|
|
489
489
|
|
|
490
490
|
# 交叉编译 (只需要安装 Go 工具链)
|
|
491
|
-
|
|
492
|
-
|
|
491
|
+
codecin program.cin --build-exe app-linux --build-target linux/amd64
|
|
492
|
+
codecin program.cin --build-exe app-mac --build-target darwin/arm64
|
|
493
493
|
```
|
|
494
494
|
|
|
495
495
|
| 目标 | 说明 |
|
|
@@ -506,10 +506,10 @@ python cpu.py program.cin --build-exe app-mac --build-target darwin/arm64
|
|
|
506
506
|
### 命令行选项
|
|
507
507
|
|
|
508
508
|
**基础执行**
|
|
509
|
-
- `
|
|
510
|
-
- `
|
|
511
|
-
- `
|
|
512
|
-
- `
|
|
509
|
+
- `codecin program.cin` - 运行CIN程序
|
|
510
|
+
- `codecin program.pl` - 运行PL程序
|
|
511
|
+
- `codecin program.asm` - 运行ASM程序
|
|
512
|
+
- `codecin program.bin` - 运行字节码
|
|
513
513
|
|
|
514
514
|
**执行路径**
|
|
515
515
|
- `--no-native` - 禁用 Go 原生库, 强制纯 Python
|
|
@@ -425,9 +425,9 @@ codecin --version
|
|
|
425
425
|
|
|
426
426
|
3. 运行:
|
|
427
427
|
```
|
|
428
|
-
|
|
428
|
+
codecin basic.cin # 唯一 CLI 入口 (自动用 Go 原生库)
|
|
429
429
|
codecin basic.cin # 安装后等价的 console script
|
|
430
|
-
|
|
430
|
+
codecin --help
|
|
431
431
|
```
|
|
432
432
|
|
|
433
433
|
> **Python 只是 CLI 外壳**: 语言实现 (`codecin/native/` 下的 Go 编译器与字节码 VM) 全部在 Go 侧,
|
|
@@ -467,11 +467,11 @@ ruff check codecin cpu.py script tests
|
|
|
467
467
|
|
|
468
468
|
```bash
|
|
469
469
|
# 本机平台
|
|
470
|
-
|
|
470
|
+
codecin program.cin --build-exe program # Windows 自动补 .exe
|
|
471
471
|
|
|
472
472
|
# 交叉编译 (只需要安装 Go 工具链)
|
|
473
|
-
|
|
474
|
-
|
|
473
|
+
codecin program.cin --build-exe app-linux --build-target linux/amd64
|
|
474
|
+
codecin program.cin --build-exe app-mac --build-target darwin/arm64
|
|
475
475
|
```
|
|
476
476
|
|
|
477
477
|
| 目标 | 说明 |
|
|
@@ -488,10 +488,10 @@ python cpu.py program.cin --build-exe app-mac --build-target darwin/arm64
|
|
|
488
488
|
### 命令行选项
|
|
489
489
|
|
|
490
490
|
**基础执行**
|
|
491
|
-
- `
|
|
492
|
-
- `
|
|
493
|
-
- `
|
|
494
|
-
- `
|
|
491
|
+
- `codecin program.cin` - 运行CIN程序
|
|
492
|
+
- `codecin program.pl` - 运行PL程序
|
|
493
|
+
- `codecin program.asm` - 运行ASM程序
|
|
494
|
+
- `codecin program.bin` - 运行字节码
|
|
495
495
|
|
|
496
496
|
**执行路径**
|
|
497
497
|
- `--no-native` - 禁用 Go 原生库, 强制纯 Python
|
|
@@ -9,18 +9,40 @@
|
|
|
9
9
|
`codecin/native/aot` 共用同一份文件 (``stub_main.go.txt``), 避免两处漂移。
|
|
10
10
|
临时包建在 `codecin-native` 模块内的 ``.aotbuild-*`` 目录: Go 工具链会忽略
|
|
11
11
|
以 '.' 开头的目录, 因此既不影响 `go build ./...`, 也不需要 replace 指令。
|
|
12
|
+
|
|
13
|
+
临时目录的生命周期 (加固, 见 docs/SUGGESTIONS_NEXT.md §3.3):
|
|
14
|
+
* 每次 :func:`build` 之前先调用 :func:`sweep_stale_build_dirs` 清理**陈旧**残留,
|
|
15
|
+
避免受限环境 (沙箱 / 只读 ACL) 下删不掉的目录无限累积;
|
|
16
|
+
* ``finally`` 里的 ``rmtree`` 失败**不再静默**: 有 logger 就 ``warning``,
|
|
17
|
+
没有 logger 时退回模块级 stdlib logger (``codecin.aot``), 绝不吞掉;
|
|
18
|
+
* 只清理 ``codecin/native/`` **本目录下**、名字带 ``.aotbuild-`` /
|
|
19
|
+
``.aotprobe-`` 前缀、且**不是符号链接**的目录, 绝不递归删除别处。
|
|
12
20
|
"""
|
|
13
21
|
|
|
22
|
+
import logging
|
|
14
23
|
import os
|
|
15
24
|
import platform
|
|
16
25
|
import secrets
|
|
17
26
|
import shutil
|
|
18
27
|
import subprocess
|
|
19
|
-
|
|
28
|
+
import time
|
|
29
|
+
from typing import List, NamedTuple, Optional
|
|
20
30
|
|
|
21
31
|
#: 仓库内 codecin-native 模块目录 (含 go.mod)。
|
|
22
32
|
_NATIVE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'native')
|
|
23
33
|
|
|
34
|
+
#: 模块级 logger: 调用方没有传 logger 时的兜底 (绝不能因为"没人接"就静默)。
|
|
35
|
+
#: 它是 ``codecin`` logger 的子 logger, 因此 CLI 构造的 Logger (RichHandler) 会
|
|
36
|
+
#: 照常渲染它; 完全没配置 logging 时 stdlib 的 lastResort 也会打到 stderr。
|
|
37
|
+
_LOGGER = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
#: AOT 临时目录名前缀 (``.aotprobe-`` 是历史遗留, 一并纳入守卫)。
|
|
40
|
+
TEMP_DIR_PREFIXES = ('.aotbuild-', '.aotprobe-')
|
|
41
|
+
|
|
42
|
+
#: 陈旧残留的默认容忍时长 (6 小时): 远大于任何一次 go build, 因此不会误删
|
|
43
|
+
#: 并发构建中的临时目录。
|
|
44
|
+
DEFAULT_STALE_AGE_SECONDS = 6 * 3600
|
|
45
|
+
|
|
24
46
|
#: 生成的 main.go 模板 (与 Go 侧共用)。
|
|
25
47
|
STUB_PATH = os.path.join(_NATIVE_DIR, 'aot', 'stub_main.go.txt')
|
|
26
48
|
|
|
@@ -130,6 +152,156 @@ def _run_go_build(cmd, mod, env, logger):
|
|
|
130
152
|
return proc, detail
|
|
131
153
|
|
|
132
154
|
|
|
155
|
+
class SweepResult(NamedTuple):
|
|
156
|
+
""":func:`sweep_stale_build_dirs` 的结果 (两个绝对路径列表)。"""
|
|
157
|
+
|
|
158
|
+
#: 成功删除的目录
|
|
159
|
+
removed: List[str]
|
|
160
|
+
#: 判定为残留但删除/读取失败的目录 (调用方应提示用户手动处理)
|
|
161
|
+
failed: List[str]
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _warn(logger, message: str) -> None:
|
|
165
|
+
"""记一条 warning; 没有 logger 时退回模块级 stdlib logger (绝不静默)。
|
|
166
|
+
|
|
167
|
+
日志本身出问题不能掩盖构建结果 (本函数常在 ``finally`` 里被调用),
|
|
168
|
+
因此这里再包一层兜底。
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
if logger is not None:
|
|
172
|
+
logger.warning(message)
|
|
173
|
+
else:
|
|
174
|
+
_LOGGER.warning(message)
|
|
175
|
+
except Exception: # noqa: BLE001 - 日志失败不得影响构建
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _debug(logger, message: str) -> None:
|
|
180
|
+
"""记一条 debug (同样带兜底)。"""
|
|
181
|
+
try:
|
|
182
|
+
if logger is not None:
|
|
183
|
+
logger.debug(message)
|
|
184
|
+
else:
|
|
185
|
+
_LOGGER.debug(message)
|
|
186
|
+
except Exception: # noqa: BLE001
|
|
187
|
+
pass
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _manual_removal_hint(path: str) -> str:
|
|
191
|
+
"""给用户的「怎么手动删掉它」提示 (Windows + POSIX 各一条)。"""
|
|
192
|
+
return (f'请手动删除该目录 —— Windows PowerShell: '
|
|
193
|
+
f'Remove-Item -LiteralPath "{path}" -Recurse -Force ; '
|
|
194
|
+
f'Linux/macOS: rm -rf "{path}"')
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _is_temp_dir_name(name: str) -> bool:
|
|
198
|
+
"""名字是否是本模块自己产生的临时目录名 (只认前缀, 不做任何路径解析)。
|
|
199
|
+
|
|
200
|
+
显式拒绝 ``.``/``..``、含路径分隔符的名字以及绝对路径 —— 这些都不可能是
|
|
201
|
+
``secrets.token_hex`` 的产物, 一旦出现就说明有人往我们手里塞了别的东西。
|
|
202
|
+
"""
|
|
203
|
+
if not name or name in ('.', '..'):
|
|
204
|
+
return False
|
|
205
|
+
if name != os.path.basename(name): # 含 / 或 \ -> 不是直接子项
|
|
206
|
+
return False
|
|
207
|
+
if os.sep in name or (os.altsep and os.altsep in name):
|
|
208
|
+
return False
|
|
209
|
+
if os.path.isabs(name):
|
|
210
|
+
return False
|
|
211
|
+
return name.startswith(TEMP_DIR_PREFIXES)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def sweep_stale_build_dirs(max_age_seconds: float = DEFAULT_STALE_AGE_SECONDS,
|
|
215
|
+
logger=None) -> SweepResult:
|
|
216
|
+
"""删除 ``codecin/native/`` 下**陈旧**的 AOT 临时构建目录。
|
|
217
|
+
|
|
218
|
+
只处理 ``codecin/native/`` 的**直接子目录** (不递归), 名字必须带
|
|
219
|
+
``.aotbuild-`` / ``.aotprobe-`` 前缀, 且 mtime 早于 ``max_age_seconds``;
|
|
220
|
+
符号链接与普通文件一律跳过。任何失败都不会抛异常, 只记录日志并把路径
|
|
221
|
+
放进 :attr:`SweepResult.failed`。
|
|
222
|
+
|
|
223
|
+
:param max_age_seconds: 容忍时长 (默认 6 小时)。``0`` 表示删除所有匹配目录
|
|
224
|
+
—— 并发构建时不要这么做。
|
|
225
|
+
:param logger: 可选 logger; 缺省时用模块级 stdlib logger。
|
|
226
|
+
:return: 被删除的路径与清理失败的路径
|
|
227
|
+
"""
|
|
228
|
+
removed: List[str] = []
|
|
229
|
+
failed: List[str] = []
|
|
230
|
+
|
|
231
|
+
root = os.path.abspath(_NATIVE_DIR)
|
|
232
|
+
try:
|
|
233
|
+
names = os.listdir(root)
|
|
234
|
+
except OSError as e: # 目录不存在 / 不可读: 尽力而为
|
|
235
|
+
_warn(logger, f'AOT: 无法扫描临时目录所在位置 {root} ({e}); 跳过清理')
|
|
236
|
+
return SweepResult(removed, failed)
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
max_age = max(0.0, float(max_age_seconds))
|
|
240
|
+
except (TypeError, ValueError):
|
|
241
|
+
max_age = float(DEFAULT_STALE_AGE_SECONDS)
|
|
242
|
+
|
|
243
|
+
now = time.time()
|
|
244
|
+
for name in names:
|
|
245
|
+
if not _is_temp_dir_name(name):
|
|
246
|
+
continue
|
|
247
|
+
path = os.path.join(root, name)
|
|
248
|
+
# 双保险: 解析后必须仍然是 root 的直接子项 (防 '..' / 绝对路径混入)
|
|
249
|
+
if os.path.dirname(os.path.abspath(path)) != root:
|
|
250
|
+
_warn(logger, f'AOT: 跳过可疑的临时目录路径: {path}')
|
|
251
|
+
continue
|
|
252
|
+
if os.path.islink(path) or not os.path.isdir(path):
|
|
253
|
+
_debug(logger, f'AOT: 跳过非普通目录的临时项: {path}')
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
age = now - os.path.getmtime(path)
|
|
258
|
+
except OSError as e:
|
|
259
|
+
failed.append(path)
|
|
260
|
+
_warn(logger, f'AOT: 无法读取残留临时目录的时间戳: {path} ({e}); '
|
|
261
|
+
f'{_manual_removal_hint(path)}')
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
if age < max_age:
|
|
265
|
+
_debug(logger, f'AOT: 临时目录仍然新鲜, 保留: {path} '
|
|
266
|
+
f'({age / 3600:.1f} 小时前)')
|
|
267
|
+
continue
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
shutil.rmtree(path)
|
|
271
|
+
except OSError as e:
|
|
272
|
+
failed.append(path)
|
|
273
|
+
_warn(logger, f'AOT: 残留临时目录清理失败: {path} '
|
|
274
|
+
f'({age / 3600:.1f} 小时前, {e}); '
|
|
275
|
+
f'{_manual_removal_hint(path)}')
|
|
276
|
+
continue
|
|
277
|
+
|
|
278
|
+
removed.append(path)
|
|
279
|
+
_debug(logger, f'AOT: 已清理陈旧临时目录: {path} '
|
|
280
|
+
f'({age / 3600:.1f} 小时前)')
|
|
281
|
+
|
|
282
|
+
if removed:
|
|
283
|
+
_debug(logger, f'AOT: 陈旧临时目录清理完成, 共 {len(removed)} 个')
|
|
284
|
+
return SweepResult(removed, failed)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _remove_temp_dir(tmp: str, logger) -> None:
|
|
288
|
+
"""删除本次构建的临时目录; 失败时告警而不是静默吞掉 (§3.3)。
|
|
289
|
+
|
|
290
|
+
``shutil.rmtree(ignore_errors=True)`` 会让「删不掉」完全静默, 于是残留
|
|
291
|
+
在受限环境 (沙箱 / 异常 ACL) 里不断累积, 最终让任何遍历仓库的工具报
|
|
292
|
+
Access is denied。这里改为: 失败 -> warning (含绝对路径与手动删除提示)。
|
|
293
|
+
"""
|
|
294
|
+
try:
|
|
295
|
+
shutil.rmtree(tmp)
|
|
296
|
+
except FileNotFoundError:
|
|
297
|
+
pass # 目录已不存在: 目的已达成
|
|
298
|
+
except Exception as e: # noqa: BLE001 - rmtree 正常只抛 OSError,
|
|
299
|
+
# 但这里处于 finally, 任何异常都不能掩盖构建结果, 一律降级为 warning。
|
|
300
|
+
_warn(logger, f'AOT: 临时构建目录清理失败, 残留目录: '
|
|
301
|
+
f'{os.path.abspath(tmp)} (原因: {e}); '
|
|
302
|
+
f'{_manual_removal_hint(tmp)}')
|
|
303
|
+
|
|
304
|
+
|
|
133
305
|
def build(bytecode: bytes,
|
|
134
306
|
mem_image: bytes,
|
|
135
307
|
out: str,
|
|
@@ -150,6 +322,14 @@ def build(bytecode: bytes,
|
|
|
150
322
|
goos, goarch = parse_target(target) if target else parse_target(host_target())
|
|
151
323
|
mod = module_dir()
|
|
152
324
|
|
|
325
|
+
# 先清掉上一次留下的陈旧残留 (默认 > 6 小时), 再建新目录: 受限环境下
|
|
326
|
+
# rmtree 可能失败, 没有这一步残留就会无限累积。
|
|
327
|
+
# 清理是尽力而为 —— 任何异常都必须吞掉, 绝不能因此让构建失败。
|
|
328
|
+
try:
|
|
329
|
+
sweep_stale_build_dirs(logger=logger)
|
|
330
|
+
except Exception as e: # noqa: BLE001
|
|
331
|
+
_debug(logger, f'AOT: 陈旧临时目录清理跳过 ({e})')
|
|
332
|
+
|
|
153
333
|
# 注意: 这里用 os.makedirs 而不是 tempfile.mkdtemp —— mkdtemp 会创建 0700
|
|
154
334
|
# 目录, 在受限环境 (沙箱 / 部分 CI 安全策略) 下随后向其中写文件会被拒绝。
|
|
155
335
|
tmp = os.path.join(mod, '.aotbuild-' + secrets.token_hex(6))
|
|
@@ -182,8 +362,9 @@ def build(bytecode: bytes,
|
|
|
182
362
|
try:
|
|
183
363
|
proc, detail = _run_go_build(cmd, mod, env, logger)
|
|
184
364
|
except FileNotFoundError as e:
|
|
185
|
-
|
|
186
|
-
|
|
365
|
+
from .environment import missing_tool_message
|
|
366
|
+
raise AotError(missing_tool_message(
|
|
367
|
+
'go', 'AOT 构建独立可执行文件')) from e
|
|
187
368
|
except subprocess.TimeoutExpired as e:
|
|
188
369
|
raise AotError('go build 超时') from e
|
|
189
370
|
if proc.returncode != 0:
|
|
@@ -199,7 +380,7 @@ def build(bytecode: bytes,
|
|
|
199
380
|
if logger:
|
|
200
381
|
logger.info(f'AOT 临时目录保留: {tmp}')
|
|
201
382
|
else:
|
|
202
|
-
|
|
383
|
+
_remove_temp_dir(tmp, logger)
|
|
203
384
|
|
|
204
385
|
|
|
205
386
|
def program_dependencies(program_file: str) -> List[str]:
|