codecin 5.8.0__tar.gz → 5.8.2__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.
Files changed (214) hide show
  1. {codecin-5.8.0 → codecin-5.8.2}/CHANGELOG.md +64 -0
  2. {codecin-5.8.0/codecin.egg-info → codecin-5.8.2}/PKG-INFO +1 -1
  3. {codecin-5.8.0 → codecin-5.8.2}/codecin/__init__.py +1 -1
  4. {codecin-5.8.0 → codecin-5.8.2}/codecin/cin.py +31 -4
  5. {codecin-5.8.0 → codecin-5.8.2}/codecin/cli.py +57 -3
  6. {codecin-5.8.0 → codecin-5.8.2}/codecin/cpu.py +50 -6
  7. {codecin-5.8.0 → codecin-5.8.2}/codecin/isa.py +4 -0
  8. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/gostd.cin +12 -3
  9. {codecin-5.8.0 → codecin-5.8.2}/codecin/memory.py +6 -1
  10. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/codegen.go +31 -2
  11. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/syscalls.go +3 -0
  12. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/isa_gen.go +3 -0
  13. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/version_gen.go +1 -1
  14. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/vm.go +65 -14
  15. {codecin-5.8.0 → codecin-5.8.2/codecin.egg-info}/PKG-INFO +1 -1
  16. {codecin-5.8.0 → codecin-5.8.2}/codecin.egg-info/SOURCES.txt +1 -0
  17. {codecin-5.8.0 → codecin-5.8.2}/examples/args_demo.cin +4 -4
  18. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_host.py +12 -2
  19. codecin-5.8.2/tests/test_issue_regress.py +263 -0
  20. {codecin-5.8.0 → codecin-5.8.2}/LICENSE +0 -0
  21. {codecin-5.8.0 → codecin-5.8.2}/MANIFEST.in +0 -0
  22. {codecin-5.8.0 → codecin-5.8.2}/README.md +0 -0
  23. {codecin-5.8.0 → codecin-5.8.2}/codecin/aot.py +0 -0
  24. {codecin-5.8.0 → codecin-5.8.2}/codecin/assembler.py +0 -0
  25. {codecin-5.8.0 → codecin-5.8.2}/codecin/cache.py +0 -0
  26. {codecin-5.8.0 → codecin-5.8.2}/codecin/config.py +0 -0
  27. {codecin-5.8.0 → codecin-5.8.2}/codecin/console.py +0 -0
  28. {codecin-5.8.0 → codecin-5.8.2}/codecin/crom.py +0 -0
  29. {codecin-5.8.0 → codecin-5.8.2}/codecin/debugger.py +0 -0
  30. {codecin-5.8.0 → codecin-5.8.2}/codecin/disasm.py +0 -0
  31. {codecin-5.8.0 → codecin-5.8.2}/codecin/environment.py +0 -0
  32. {codecin-5.8.0 → codecin-5.8.2}/codecin/errors.py +0 -0
  33. {codecin-5.8.0 → codecin-5.8.2}/codecin/jit.py +0 -0
  34. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/array.cin +0 -0
  35. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/bigint.cin +0 -0
  36. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/bits.cin +0 -0
  37. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/bitset.cin +0 -0
  38. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/codec.cin +0 -0
  39. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/combin.cin +0 -0
  40. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/conv.cin +0 -0
  41. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/cppstd.cin +0 -0
  42. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/cstd.cin +0 -0
  43. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/csv.cin +0 -0
  44. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/dp.cin +0 -0
  45. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/fmt.cin +0 -0
  46. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/frac.cin +0 -0
  47. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/graph.cin +0 -0
  48. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/gui.cin +0 -0
  49. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/hash.cin +0 -0
  50. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/heap.cin +0 -0
  51. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/io.cin +0 -0
  52. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/json.cin +0 -0
  53. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/key.cin +0 -0
  54. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/math.cin +0 -0
  55. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/matrix.cin +0 -0
  56. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/path.cin +0 -0
  57. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/queue.cin +0 -0
  58. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/rand.cin +0 -0
  59. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/set.cin +0 -0
  60. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/sort.cin +0 -0
  61. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/stat.cin +0 -0
  62. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/str.cin +0 -0
  63. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/termux.cin +0 -0
  64. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/test.cin +0 -0
  65. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/text.cin +0 -0
  66. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/time.cin +0 -0
  67. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/token.cin +0 -0
  68. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/tree.cin +0 -0
  69. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/unionfind.cin +0 -0
  70. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/validate.cin +0 -0
  71. {codecin-5.8.0 → codecin-5.8.2}/codecin/lib/vec.cin +0 -0
  72. {codecin-5.8.0 → codecin-5.8.2}/codecin/logger.py +0 -0
  73. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/aot/aot.go +0 -0
  74. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/aot/stub_main.go.txt +0 -0
  75. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/build.ps1 +0 -0
  76. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/build.sh +0 -0
  77. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/compile_test.go +0 -0
  78. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/parser.go +0 -0
  79. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/tokenizer.go +0 -0
  80. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/compiler/types.go +0 -0
  81. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/args.go +0 -0
  82. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/audio.go +0 -0
  83. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/audio_other.go +0 -0
  84. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/audio_test.go +0 -0
  85. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/audio_windows.go +0 -0
  86. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/canvas.go +0 -0
  87. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/console_other.go +0 -0
  88. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/console_windows.go +0 -0
  89. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/crom.go +0 -0
  90. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/encode.go +0 -0
  91. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/engine_test.go +0 -0
  92. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/gui.go +0 -0
  93. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/gui_stub.go +0 -0
  94. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/gui_test.go +0 -0
  95. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/gui_windows.go +0 -0
  96. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/gui_x11.go +0 -0
  97. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/host_test.go +0 -0
  98. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/hostcrypto.go +0 -0
  99. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/hostdesktop.go +0 -0
  100. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/hostnet.go +0 -0
  101. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard.go +0 -0
  102. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_other.go +0 -0
  103. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_stub.go +0 -0
  104. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_termios_darwin.go +0 -0
  105. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_termios_linux.go +0 -0
  106. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_test.go +0 -0
  107. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_windows.go +0 -0
  108. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/keyboard_windows_test.go +0 -0
  109. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/mem_other.go +0 -0
  110. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/mem_windows.go +0 -0
  111. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/stdin.go +0 -0
  112. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/stdin_other.go +0 -0
  113. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/stdin_windows.go +0 -0
  114. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/system.go +0 -0
  115. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/engine/termux.go +0 -0
  116. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/go.mod +0 -0
  117. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/ir/ir.go +0 -0
  118. {codecin-5.8.0 → codecin-5.8.2}/codecin/native/main.go +0 -0
  119. {codecin-5.8.0 → codecin-5.8.2}/codecin/native.py +0 -0
  120. {codecin-5.8.0 → codecin-5.8.2}/codecin/registers.py +0 -0
  121. {codecin-5.8.0 → codecin-5.8.2}/codecin/stats.py +0 -0
  122. {codecin-5.8.0 → codecin-5.8.2}/codecin/stdlib.py +0 -0
  123. {codecin-5.8.0 → codecin-5.8.2}/codecin/version.py +0 -0
  124. {codecin-5.8.0 → codecin-5.8.2}/codecin.egg-info/dependency_links.txt +0 -0
  125. {codecin-5.8.0 → codecin-5.8.2}/codecin.egg-info/entry_points.txt +0 -0
  126. {codecin-5.8.0 → codecin-5.8.2}/codecin.egg-info/requires.txt +0 -0
  127. {codecin-5.8.0 → codecin-5.8.2}/codecin.egg-info/top_level.txt +0 -0
  128. {codecin-5.8.0 → codecin-5.8.2}/examples/asm_constants.asm +0 -0
  129. {codecin-5.8.0 → codecin-5.8.2}/examples/bitwise_builtins.cin +0 -0
  130. {codecin-5.8.0 → codecin-5.8.2}/examples/control_flow.cin +0 -0
  131. {codecin-5.8.0 → codecin-5.8.2}/examples/enum_range_for.cin +0 -0
  132. {codecin-5.8.0 → codecin-5.8.2}/examples/gui_demo.cin +0 -0
  133. {codecin-5.8.0 → codecin-5.8.2}/examples/literals_types.cin +0 -0
  134. {codecin-5.8.0 → codecin-5.8.2}/examples/local_audio.cin +0 -0
  135. {codecin-5.8.0 → codecin-5.8.2}/examples/modules_demo.cin +0 -0
  136. {codecin-5.8.0 → codecin-5.8.2}/examples/stdlib_demo.cin +0 -0
  137. {codecin-5.8.0 → codecin-5.8.2}/examples/system_interaction.cin +0 -0
  138. {codecin-5.8.0 → codecin-5.8.2}/misc/vim/ftdetect/codecin.vim +0 -0
  139. {codecin-5.8.0 → codecin-5.8.2}/misc/vim/syntax/cin.vim +0 -0
  140. {codecin-5.8.0 → codecin-5.8.2}/misc/vim/syntax/codecinasm.vim +0 -0
  141. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/.vscodeignore +0 -0
  142. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/README.md +0 -0
  143. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/build.bat +0 -0
  144. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/language-configuration.json +0 -0
  145. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/package.json +0 -0
  146. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/snippets/cin.json +0 -0
  147. {codecin-5.8.0 → codecin-5.8.2}/misc/vscode-cin/syntaxes/cin.tmLanguage.json +0 -0
  148. {codecin-5.8.0 → codecin-5.8.2}/pyproject.toml +0 -0
  149. {codecin-5.8.0 → codecin-5.8.2}/script/bump_version.py +0 -0
  150. {codecin-5.8.0 → codecin-5.8.2}/script/check_paths.py +0 -0
  151. {codecin-5.8.0 → codecin-5.8.2}/script/gen_isa_docs.py +0 -0
  152. {codecin-5.8.0 → codecin-5.8.2}/script/gen_native_isa.py +0 -0
  153. {codecin-5.8.0 → codecin-5.8.2}/setup.cfg +0 -0
  154. {codecin-5.8.0 → codecin-5.8.2}/setup.py +0 -0
  155. {codecin-5.8.0 → codecin-5.8.2}/tests/test_aggregate_and_const.py +0 -0
  156. {codecin-5.8.0 → codecin-5.8.2}/tests/test_all_libs_together.py +0 -0
  157. {codecin-5.8.0 → codecin-5.8.2}/tests/test_aot.py +0 -0
  158. {codecin-5.8.0 → codecin-5.8.2}/tests/test_assembler_ext.py +0 -0
  159. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cache.py +0 -0
  160. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_host_ext.py +0 -0
  161. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_new_features.py +0 -0
  162. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_syntax.py +0 -0
  163. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_syntax_ext.py +0 -0
  164. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cin_system.py +0 -0
  165. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cli.py +0 -0
  166. {codecin-5.8.0 → codecin-5.8.2}/tests/test_compiler_errors.py +0 -0
  167. {codecin-5.8.0 → codecin-5.8.2}/tests/test_cpu_interpreted.py +0 -0
  168. {codecin-5.8.0 → codecin-5.8.2}/tests/test_debugger.py +0 -0
  169. {codecin-5.8.0 → codecin-5.8.2}/tests/test_environment.py +0 -0
  170. {codecin-5.8.0 → codecin-5.8.2}/tests/test_examples.py +0 -0
  171. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_ab.py +0 -0
  172. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_crom_mmu.py +0 -0
  173. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_import.py +0 -0
  174. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_importloc.py +0 -0
  175. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_mmu.py +0 -0
  176. {codecin-5.8.0 → codecin-5.8.2}/tests/test_features_remote.py +0 -0
  177. {codecin-5.8.0 → codecin-5.8.2}/tests/test_gui.py +0 -0
  178. {codecin-5.8.0 → codecin-5.8.2}/tests/test_index_subscript_type.py +0 -0
  179. {codecin-5.8.0 → codecin-5.8.2}/tests/test_isa_dispatch.py +0 -0
  180. {codecin-5.8.0 → codecin-5.8.2}/tests/test_isa_single_source.py +0 -0
  181. {codecin-5.8.0 → codecin-5.8.2}/tests/test_keyboard.py +0 -0
  182. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_bigint.py +0 -0
  183. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_bitset.py +0 -0
  184. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_codec.py +0 -0
  185. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_combin.py +0 -0
  186. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_compat.py +0 -0
  187. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_csv.py +0 -0
  188. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_dp.py +0 -0
  189. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_fmt.py +0 -0
  190. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_frac.py +0 -0
  191. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_graph.py +0 -0
  192. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_heap.py +0 -0
  193. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_path.py +0 -0
  194. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_set.py +0 -0
  195. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_text.py +0 -0
  196. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_token.py +0 -0
  197. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_tree.py +0 -0
  198. {codecin-5.8.0 → codecin-5.8.2}/tests/test_lib_unionfind.py +0 -0
  199. {codecin-5.8.0 → codecin-5.8.2}/tests/test_libs.py +0 -0
  200. {codecin-5.8.0 → codecin-5.8.2}/tests/test_libs_ext.py +0 -0
  201. {codecin-5.8.0 → codecin-5.8.2}/tests/test_literals_and_bom.py +0 -0
  202. {codecin-5.8.0 → codecin-5.8.2}/tests/test_memory_protection.py +0 -0
  203. {codecin-5.8.0 → codecin-5.8.2}/tests/test_native_hardening.py +0 -0
  204. {codecin-5.8.0 → codecin-5.8.2}/tests/test_native_lib_lookup.py +0 -0
  205. {codecin-5.8.0 → codecin-5.8.2}/tests/test_nested_subscript_codegen.py +0 -0
  206. {codecin-5.8.0 → codecin-5.8.2}/tests/test_no_go_cli.py +0 -0
  207. {codecin-5.8.0 → codecin-5.8.2}/tests/test_p0_fixes.py +0 -0
  208. {codecin-5.8.0 → codecin-5.8.2}/tests/test_packaging.py +0 -0
  209. {codecin-5.8.0 → codecin-5.8.2}/tests/test_paths_consistency.py +0 -0
  210. {codecin-5.8.0 → codecin-5.8.2}/tests/test_struct_value_semantics.py +0 -0
  211. {codecin-5.8.0 → codecin-5.8.2}/tests/test_switch_semantics.py +0 -0
  212. {codecin-5.8.0 → codecin-5.8.2}/tests/test_three_paths.py +0 -0
  213. {codecin-5.8.0 → codecin-5.8.2}/tests/test_version.py +0 -0
  214. {codecin-5.8.0 → codecin-5.8.2}/tests/test_workflows.py +0 -0
@@ -5,6 +5,70 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## [5.8.2] - 2026-10-04
9
+
10
+ 一次以「真实压测程序暴露的错误信息与栈安全」为主线的修复发布。核心结论:
11
+ 5.5.3 的浮点下标修复在三条执行路径均有效(`a[(n * p) / 100]` 一类变量参与
12
+ 的浮点表达式同样覆盖);用户在 Termux 上报告的 `address ffffffffffffc6f8
13
+ out of bounds` 实为**局部大数组把栈推成负地址**——`int lat[10000]` 需要
14
+ 80 KB 局部空间,超过默认 64 KB 内存后 SP 绕回,越界检查检查的是绕回后的
15
+ 地址。为此新增带防护的帧分配系统调用(SYS 137),并全面改进运行时/编译期
16
+ 错误信息、补齐 CLI 直传参数与高精度计时。
17
+
18
+ ### 修复 (Fixed)
19
+
20
+ #### 局部大数组撑爆栈(静默生成负地址)
21
+ - **函数序言的帧分配改为带防护的系统调用**。此前 prologue 用裸 `ADDI sp, sp,
22
+ -frame_bytes` 递减栈指针,局部数组总大小超过可用内存时 SP 绕回为巨大无符号
23
+ 值(如 0xFFFFFFFFFFFFC6F8),后续所有访问都指向"负地址",报错只看到一句
24
+ out of bounds,看不出真因。现在两侧编译器(`cin.py` / `codegen.go`)改为
25
+ `SYS ALLOCFRAME`:VM 侧用**有符号比较**在分配前检查栈余量(含 4 KB 警戒
26
+ 线),不足时直接报
27
+ `Stack overflow: frame needs N bytes, stack headroom only M bytes (...)
28
+ Try --mem-size (default 65536) or smaller local arrays`,
29
+ 不再让绕回地址流入访存路径。Python 解释器、JIT、Go 原生三条路径语义一致。
30
+ - **负地址越界提示兜底**:地址 >= 2^63 的越界报错(Python `memory.py` 与
31
+ Go `checkAddr`)追加
32
+ `(negative address: stack overflow or bad pointer?)`,把"看起来像随机大数"
33
+ 的地址翻译成可排查的方向。
34
+
35
+ #### 错误信息补全(问题 2/4/5)
36
+ - **Heap exhausted 附用量与建议**:三处堆耗尽点(malloc / 字符串拼接 / 字符串
37
+ 操作)在 Python 与 Go 两侧逐字一致地报
38
+ `Heap exhausted: need N bytes, free M bytes (heap 0x...0x...).
39
+ Try --mem-size (default 65536) or reduce allocations`。
40
+ - **非常量数组长度的编译期报错附 hint**:
41
+ `array lengths must be compile-time constants; declare it as
42
+ \`const int NAME = ...\`; variable-length arrays are not supported —
43
+ use a fixed-size array plus a count variable`。
44
+ - **`float(x)` / `int(x)` 报错附替代写法**:提示使用 `to_float(x)` / `to_int(x)`
45
+ 或依赖混合表达式的隐式提升。
46
+
47
+ #### 兼容层与文档
48
+ - `gostd.cin` 头注释明确列出当前覆盖的包(strings / strconv / math / slices /
49
+ os.Args)与**未覆盖项**(time、os 文件读写、net/http、sync),并指向对应
50
+ 内建(`time_ms/time_us/time_ns`、`file_*` 函数族),避免"Go 标准库兼容层"
51
+ 的命名让人误以为常用包会逐步全覆盖。
52
+
53
+ ### 新增 (Added)
54
+
55
+ #### CLI 程序名后直传参数
56
+ - `codecin 压测.cin https://example.com 24` 现在可用:程序文件之后的裸参数
57
+ 原样传给 CIN 程序(`arg_count()` / `arg(i)`),已知 CLI 选项放在程序之前或
58
+ 之后均可识别;形如选项的直传参数给出 stderr 提示并用 `--` 显式分隔。
59
+ `--` 分隔符行为不变且优先级最高,`--help` 新增 Program arguments 说明段。
60
+
61
+ #### 高精度计时 `time_us()` / `time_ns()`(SYS 138/139)
62
+ - 微秒 / 纳秒级单调计时,补齐 `time_ms()` 只能测毫秒的短板(压测与微基准
63
+ 基础设施)。两侧编译器同步登记,解释器 / JIT / 原生三条路径均可用;
64
+ 与 ALLOCFRAME 同属核心 VM 机制,不触发沙箱门禁与原生路径限定。
65
+
66
+ #### 显式类型转换 `to_int()` / `to_float()`
67
+ - 数值类型(int/float/bool)间的显式转换,语义与隐式转换一致(float→int 向零
68
+ 截断)。非数值参数在编译期报错并说明。
69
+
70
+ ---
71
+
8
72
  ## [5.8.0] - 2026-10-04
9
73
 
10
74
  一次「图形、媒体与跨平台兼容」发布:新增 **GUI 窗口**(Windows Win32 /
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecin
3
- Version: 5.8.0
3
+ Version: 5.8.2
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
@@ -1,4 +1,4 @@
1
- __version__ = "5.8.0"
1
+ __version__ = "5.8.2"
2
2
  __author__ = "ByUsi Studio"
3
3
 
4
4
  from .config import Config
@@ -210,6 +210,8 @@ HOST_BUILTINS = {
210
210
  'chdir': (Syscall.CHDIR, 1, 'int'),
211
211
  # 时间与系统信息
212
212
  'time_ms': (Syscall.TIMEMS, 0, 'int'),
213
+ 'time_us': (Syscall.TIMEUS, 0, 'int'),
214
+ 'time_ns': (Syscall.TIMENS, 0, 'int'),
213
215
  'sleep_ms': (Syscall.SLEEPMS, 1, 'int'),
214
216
  'cpu_count': (Syscall.CPUCOUNT, 0, 'int'),
215
217
  'arch_name': (Syscall.ARCHNAME, 0, 'string'),
@@ -953,7 +955,11 @@ class Parser:
953
955
  return ('int', self.enums[node[1]])
954
956
  raise CompilerError(
955
957
  f"Constant expression uses non-constant name '{node[1]}' "
956
- f"at {self._loc()}")
958
+ f"at {self._loc()} "
959
+ "(hint: array lengths must be compile-time constants; "
960
+ f"declare it as `const int {node[1]} = ...`; "
961
+ "variable-length arrays are not supported — use a fixed-size "
962
+ "array plus a count variable)")
957
963
  if kind == 'neg':
958
964
  ctype, value = self._const_value_ast(node[1])
959
965
  if ctype == 'string':
@@ -1996,12 +2002,15 @@ class CodeGen:
1996
2002
  self.locals[pname] = (ptype, poff, False)
1997
2003
 
1998
2004
  self.label(f.name)
1999
- # prologue: 保存调用方 FP, 建立帧指针, 分配局部空间
2005
+ # prologue: 保存调用方 FP, 建立帧指针, 分配局部空间。
2006
+ # 帧分配走 SYS ALLOCFRAME (带栈溢出防护): 此前直接 ADDI SP 减帧长,
2007
+ # 局部大数组会把 SP 推到负地址 —— 轻则报晦涩的越界地址
2008
+ # (如 address ffff...c6f8), 重则静默覆盖全局/堆内存。
2000
2009
  self.emit('PUSH', self.reg(29))
2001
2010
  self.emit('MOV', self.reg(29), self.reg(32)) # FP = SP
2002
2011
  if self.frame_bytes:
2003
- self.emit('ADDI', self.reg(0), self.reg(32), self.imm(-self.frame_bytes))
2004
- self.emit('MOV', self.reg(32), self.reg(0))
2012
+ self.emit('MOV', self.reg(0), self.imm(self.frame_bytes))
2013
+ self.emit('SYS', self.imm(Syscall.ALLOCFRAME))
2005
2014
 
2006
2015
  # struct 局部变量: 堆分配对象 (槽里存对象指针, 与全局 struct 同一模型)
2007
2016
  for _name, (t, loff, _is_block) in list(self.locals.items()):
@@ -3543,6 +3552,18 @@ class CodeGen:
3543
3552
  'rtrim': Syscall.RTRIM}[name]
3544
3553
  self.emit('SYS', self.imm(sys_id))
3545
3554
  return 'string'
3555
+ if name in ('to_int', 'to_float'):
3556
+ # 显式类型转换: to_int(x) 向零截断 (与 int x = 1.9 一致),
3557
+ # to_float(x) 整数提升为浮点。参数类型静态已知, 非数值报编译错。
3558
+ t = self.gen_value(args[0])
3559
+ target = 'int' if name == 'to_int' else 'float'
3560
+ if t not in ('int', 'float', 'bool'):
3561
+ raise CompilerError(
3562
+ f"{name}() expects a numeric argument, got {t} "
3563
+ f"at {self._loc()}"
3564
+ + (f" (hint: use atoi() to parse a string)" if t == 'string' else ""))
3565
+ self._convert(t, target)
3566
+ return target
3546
3567
  if name == 'atoi':
3547
3568
  self.gen_value(args[0])
3548
3569
  self.emit('SYS', self.imm(Syscall.ATOI))
@@ -3562,6 +3583,12 @@ class CodeGen:
3562
3583
  return 'int'
3563
3584
 
3564
3585
  # 用户函数 (已在 _gen_call 开头优先分派; 走到这里说明名字未知)
3586
+ if name in ('int', 'float'):
3587
+ # 常见迁移习惯: C/Python 风格的显式转换函数。给出可操作的替代写法。
3588
+ raise CompilerError(
3589
+ f"Unknown function: {name} (hint: use "
3590
+ f"to_{name}(x) for explicit conversion, or rely on implicit "
3591
+ "promotion in mixed int/float expressions)")
3565
3592
  raise CompilerError(f"Unknown function: {name}")
3566
3593
 
3567
3594
  @staticmethod
@@ -17,7 +17,11 @@ from .console import Colors, Console, Panel
17
17
  HELP_INTRO = f"""{Colors.colorize(f'Code CIN v{__version__}', Colors.CYAN, True)}
18
18
 
19
19
  {Colors.colorize('Usage:', Colors.YELLOW)}
20
- codecin <program.[cin|pl|asm|bin]> [options]
20
+ codecin [options] <program.[cin|pl|asm|bin]> [args...]
21
+
22
+ {Colors.colorize('Program arguments:', Colors.YELLOW)}
23
+ program 之后的裸参数原样传给 CIN 程序 (arg_count()/arg(i) 读取);
24
+ CLI 选项放在 program 之前或之后均可识别, 形如选项的参数请用 `--` 显式分隔。
21
25
 
22
26
  {Colors.colorize('Supported formats:', Colors.YELLOW)}
23
27
  .cin CIN 高级语言 (函数/struct/数组/浮点/字符串)
@@ -219,6 +223,43 @@ def _run_aot_build(ns: argparse.Namespace, console, program_file: str,
219
223
  return 0
220
224
 
221
225
 
226
+ def _extract_program_args(args: List[str], parser: argparse.ArgumentParser):
227
+ """把程序文件之后的裸参数透传给 CIN 程序 (arg_count()/arg(i))。
228
+
229
+ 规则 (向后兼容): 第一个非选项 token 是程序文件; 此后遇到已知 CLI 选项
230
+ (及其取值) 仍归 CLI 解析, 其余裸 token 归程序参数。`--` 分隔的参数已在
231
+ main 里摘出, 优先级更高。返回 (cli_args, program_args)。
232
+ """
233
+ takes_value = {}
234
+ for act in parser._actions: # noqa: SLF001 - argparse 无公开枚举接口
235
+ for s in getattr(act, 'option_strings', []):
236
+ takes_value[s] = getattr(act, 'nargs', None) != 0
237
+ cli_args: List[str] = []
238
+ prog_args: List[str] = []
239
+ seen_prog = False
240
+ i, n = 0, len(args)
241
+ while i < n:
242
+ tok = args[i]
243
+ # --opt=value 形式按其选项名识别
244
+ optname = tok.split('=', 1)[0] if tok.startswith('--') else tok
245
+ if optname in takes_value:
246
+ cli_args.append(tok)
247
+ if takes_value[optname] and '=' not in tok:
248
+ i += 1
249
+ if i < n:
250
+ cli_args.append(args[i])
251
+ i += 1
252
+ continue
253
+ if not seen_prog:
254
+ cli_args.append(tok)
255
+ seen_prog = True
256
+ i += 1
257
+ continue
258
+ prog_args.append(tok)
259
+ i += 1
260
+ return cli_args, prog_args
261
+
262
+
222
263
  def main(argv: Optional[List[str]] = None) -> int:
223
264
  args = list(sys.argv[1:] if argv is None else argv)
224
265
 
@@ -246,8 +287,20 @@ def main(argv: Optional[List[str]] = None) -> int:
246
287
 
247
288
  console = Console()
248
289
  parser = build_parser()
290
+
291
+ # 程序文件之后的裸参数透传给 CIN 程序 (问题反馈 #3): 已知 CLI 选项
292
+ # (含取值) 仍归 argparse, 其余 token 归 arg_count()/arg(i)。
293
+ cli_args, direct_args = _extract_program_args(args, parser)
294
+ if direct_args:
295
+ for tok in direct_args:
296
+ if tok.startswith('-') and tok not in ('-',) \
297
+ and not tok.lstrip('-').split('=')[0].isdigit():
298
+ sys.stderr.write(
299
+ f"note: {tok!r} 不是 CLI 选项, 已作为程序参数传递 "
300
+ f"(arg_count/arg); 如需强制传参请用 `-- {tok}`\n")
301
+
249
302
  try:
250
- ns = parser.parse_args(args)
303
+ ns = parser.parse_args(cli_args)
251
304
  except SystemExit as e:
252
305
  # argparse 错误 (未知选项/非法数值): 已打印 usage, 返回其退出码
253
306
  return int(e.code) if e.code is not None else 2
@@ -278,7 +331,8 @@ def main(argv: Optional[List[str]] = None) -> int:
278
331
 
279
332
  config = Config()
280
333
  _apply_namespace(config, ns)
281
- config.program_args = program_args
334
+ # 直传参数与 `--` 后参数合并 (直传在前, 位置顺序与命令行一致)
335
+ config.program_args = direct_args + program_args
282
336
  config.validate()
283
337
 
284
338
  program_file = ns.program
@@ -23,6 +23,12 @@ Instruction = Tuple[str, List[Operand]]
23
23
  MASK64 = 0xFFFFFFFFFFFFFFFF
24
24
  MASK32 = 0xFFFFFFFF
25
25
 
26
+ # 核心 VM 机制系统调用: 不触碰宿主状态, 沙箱模式同样放行 (与 SYS < AUDIOPLAY
27
+ # 的数学/字符串类内建同级)。文本语义必须与 Go 引擎 vm.go 保持一致。
28
+ _CORE_SYS_CALLS = frozenset({
29
+ Syscall.ALLOCFRAME, Syscall.TIMEUS, Syscall.TIMENS,
30
+ })
31
+
26
32
 
27
33
  def _f_to_bits(f: float) -> int:
28
34
  return struct.unpack('<Q', struct.pack('<d', f))[0]
@@ -85,7 +91,8 @@ class CPU:
85
91
  self.pstate: Dict[str, bool] = {'N': False, 'Z': False, 'C': False, 'V': False}
86
92
  self.pc = 0
87
93
  self.sp = (config.mem_size - Constants.STACK_SLOT) & ~0x7
88
- self.heap_ptr = config.mem_size // 2
94
+ self.heap_base = config.mem_size // 2
95
+ self.heap_ptr = self.heap_base
89
96
 
90
97
  self.logger.dump("CPU 初始化", {
91
98
  'memory': f"0x{config.mem_size:x} bytes",
@@ -1153,7 +1160,11 @@ class CPU:
1153
1160
  ptr = self.heap_ptr
1154
1161
  self.heap_ptr += size
1155
1162
  if self.heap_ptr > self.sp:
1156
- raise ExecutionError("Heap exhausted (string operation)")
1163
+ free = max(self.sp - ptr, 0)
1164
+ raise ExecutionError(
1165
+ f"Heap exhausted (string operation): need {size} bytes,"
1166
+ f" free {free} bytes (heap 0x{self.heap_base:x}..0x{self.sp:x})."
1167
+ " Try --mem-size (default 65536) or reduce allocations")
1157
1168
  self.memory.write_block(ptr, data)
1158
1169
  return ptr
1159
1170
 
@@ -1170,7 +1181,9 @@ class CPU:
1170
1181
  call_id = args[0][1]
1171
1182
  # 沙箱模式: 拦截全部宿主能力 (音频/画布/文件/进程/环境/网络/Termux),
1172
1183
  # 只放行数学/字符串/内存/输出类内建。原生路径在 _try_native_run 已强制回退。
1173
- if self.config.sandbox_mode and call_id >= Syscall.AUDIOPLAY:
1184
+ # 核心机制系统调用 (_CORE_SYS_CALLS) 不触碰宿主状态, 沙箱内照常放行。
1185
+ if (self.config.sandbox_mode and call_id >= Syscall.AUDIOPLAY
1186
+ and call_id not in _CORE_SYS_CALLS):
1174
1187
  raise ExecutionError(
1175
1188
  "Host capability disabled in sandbox mode (SYS "
1176
1189
  f"{call_id}: {Syscall(call_id).name if call_id in Syscall._value2member_map_ else 'UNKNOWN'})")
@@ -1183,7 +1196,30 @@ class CPU:
1183
1196
  self.logger.trace(f" SYS #{call_id} ({name}) "
1184
1197
  f"x0=0x{x0:x} x1=0x{x1:x} x2=0x{x2:x}")
1185
1198
 
1186
- if call_id == Syscall.ABS:
1199
+ if call_id == Syscall.ALLOCFRAME:
1200
+ # 函数序言的帧分配 (核心机制, 沙箱放行): 带溢出防护的 SP 递减。
1201
+ # 此前 prologue 直接 ADDI SP, SP, -frame_bytes, 局部大数组会把 SP
1202
+ # 推到负地址 —— 轻则报晦涩的 "address ffff... out of bounds",
1203
+ # 重则静默覆盖全局/堆内存。消息文本必须与 Go 引擎 vm.go 一致。
1204
+ fb = x0
1205
+ guard = self.heap_ptr + 4096
1206
+ # 按有符号比较: SP 绕回 (负地址) 必须判定为溢出, 不能先按
1207
+ # 2^64 取模再比大小 (绕回值会显得巨大而漏判)。
1208
+ new_sp = self.sp - fb
1209
+ if new_sp < guard:
1210
+ avail = max(self.sp - guard, 0)
1211
+ raise ExecutionError(
1212
+ f"Stack overflow: frame needs {fb} bytes, stack headroom "
1213
+ f"only {avail} bytes (SP 0x{self.sp:x}, guard "
1214
+ f"0x{guard:x}, memory {self.config.mem_size} bytes). "
1215
+ "Try --mem-size (default 65536) or smaller local arrays")
1216
+ self.sp = new_sp & MASK64
1217
+ self._set_reg(0, self.sp)
1218
+ elif call_id in (Syscall.TIMEUS, Syscall.TIMENS):
1219
+ # 高精度计时: Unix 纪元微秒/纳秒 (与 Go time.Now() 同基, 非单调钟)
1220
+ ns = time.time_ns()
1221
+ self._set_reg(0, ns // 1000 if call_id == Syscall.TIMEUS else ns)
1222
+ elif call_id == Syscall.ABS:
1187
1223
  self._set_reg(0, abs(x0 if x0 < (1 << 63) else x0 - (1 << 64)))
1188
1224
  elif call_id in (Syscall.SQRT,):
1189
1225
  # 负数定义域: 与 Go 路径一致返回 NaN (不抛 CPython 内部异常)
@@ -1258,7 +1294,11 @@ class CPU:
1258
1294
  ptr = self.heap_ptr
1259
1295
  self.heap_ptr += size
1260
1296
  if self.heap_ptr > self.sp:
1261
- raise ExecutionError("Heap exhausted")
1297
+ free = max(self.sp - ptr, 0)
1298
+ raise ExecutionError(
1299
+ f"Heap exhausted: need {size} bytes, free {free} bytes"
1300
+ f" (heap 0x{self.heap_base:x}..0x{self.sp:x})."
1301
+ " Try --mem-size (default 65536) or reduce allocations")
1262
1302
  self._set_reg(0, ptr)
1263
1303
  elif call_id == Syscall.PRINT_FLOAT:
1264
1304
  self._emit_text(_format_float(_bits_to_f(x0)))
@@ -1282,7 +1322,11 @@ class CPU:
1282
1322
  ptr = self.heap_ptr
1283
1323
  self.heap_ptr += size
1284
1324
  if self.heap_ptr > self.sp:
1285
- raise ExecutionError("Heap exhausted (string concat)")
1325
+ free = max(self.sp - ptr, 0)
1326
+ raise ExecutionError(
1327
+ f"Heap exhausted (string concat): need {size} bytes,"
1328
+ f" free {free} bytes (heap 0x{self.heap_base:x}..0x{self.sp:x})."
1329
+ " Try --mem-size (default 65536) or reduce allocations")
1286
1330
  self.memory.write_block(ptr, data)
1287
1331
  self._set_reg(0, ptr)
1288
1332
  elif call_id == Syscall.BOOL_STR:
@@ -275,6 +275,10 @@ class Syscall(IntEnum):
275
275
  AUDIOPAUSE = 134 # audio_pause() -> 0 成功 / -1 (无播放或已暂停)
276
276
  AUDIORESUME = 135 # audio_resume() -> 0 成功 / -1 (无暂停可恢复)
277
277
  AUDIOLEVEL = 136 # audio_level() -> 当前音量 0..100 (audio_volume 设置值)
278
+ # ---- 核心 VM 机制 (非宿主能力: 解释器/沙箱/原生三路径都可用) ----
279
+ ALLOCFRAME = 137 # alloc_frame(x0=字节数): SP -= x0; 低于堆警戒线则中止
280
+ TIMEUS = 138 # time_us() -> 单调微秒计时 (高精度基准测试用)
281
+ TIMENS = 139 # time_ns() -> 单调纳秒计时 (time_us 的高分辨率版本)
278
282
 
279
283
 
280
284
  class Cond:
@@ -1,9 +1,18 @@
1
1
  // Code CIN 官方标准库: Go 标准库兼容层 (gostd)
2
2
  // 用法: import "gostd.cin"
3
3
  //
4
- // 以 pkg.Func 命名习惯提供 strings / strconv / math / slices / os 的
5
- // 常用函数 (go_strings_contains 对应 strings.Contains)。命名里的包段
6
- // 与 Go 文档一一对应, 便于从 Go 移植或查阅语义。
4
+ // 覆盖范围 (纯 CIN 实现, 与 Go 标准库命名的对应关系):
5
+ // strings —— Contains/Index/重复/大小写/裁剪/前后缀/替换等常用函数
6
+ // strconv —— Itoa/Atoi/ParseBool/FormatFloat(经 ftoa) 等转换
7
+ // math —— Sqrt/Abs/Floor/Ceil/Round/Pow 等包装
8
+ // slices —— Contains/Index/Sort(经排序内建)/Reverse 等常用操作
9
+ // os —— 仅 os.Args (go_os_args_len / go_os_args_get)
10
+ // 未覆盖 (避免误解): time、os 文件读写、net/http、sync 等包暂无兼容层 ——
11
+ // 计时请用内建 time_ms/time_us/time_ns, 文件读写用内建 file_* 函数族。
12
+ //
13
+ // 以 pkg.Func 命名习惯提供上述包的常用函数 (go_strings_contains 对应
14
+ // strings.Contains)。命名里的包段与 Go 文档一一对应, 便于从 Go 移植或
15
+ // 查阅语义。
7
16
  // 注意: go_os_args_len / go_os_args_get 依赖命令行参数内建 (arg_count /
8
17
  // arg, SYS 129..130), 需要原生路径 (CLI `--` 传参或 AOT 产物 os.Args)。
9
18
 
@@ -179,9 +179,14 @@ class FastMemory:
179
179
 
180
180
  def _check_bounds(self, addr: int, size: int = 1) -> None:
181
181
  if not 0 <= addr <= self._size - size:
182
+ hint = ""
183
+ if addr >= (1 << 63):
184
+ # 按位模 2^64 后为负数: 典型成因是栈溢出 (SP 被推到负地址)
185
+ # 或野指针。可读性提示, 与 Go 引擎 vm.go 的文案保持一致。
186
+ hint = " (negative address: stack overflow or bad pointer?)"
182
187
  raise MemoryAccessError(
183
188
  f"Address 0x{addr:x} out of bounds (memory size 0x{self._size:x}, "
184
- f"access width {size})")
189
+ f"access width {size}){hint}")
185
190
 
186
191
  def _check_protection(self, addr: int, access: str) -> None:
187
192
  if not self.check_access(addr, access):
@@ -79,6 +79,8 @@ var hostBuiltins = map[string]hostBuiltin{
79
79
  "chdir": {SysCHDIR, 1, kInt},
80
80
  // 时间与系统信息
81
81
  "time_ms": {SysTIMEMS, 0, kInt},
82
+ "time_us": {SysTIMEUS, 0, kInt},
83
+ "time_ns": {SysTIMENS, 0, kInt},
82
84
  "sleep_ms": {SysSLEEPMS, 1, kInt},
83
85
  "cpu_count": {SysCPUCOUNT, 0, kInt},
84
86
  "arch_name": {SysARCHNAME, 0, kString},
@@ -342,9 +344,11 @@ func (c *compiler) genFunctionBody(f *FuncDef) {
342
344
  c.label(f.name)
343
345
  c.emit("PUSH", c.reg(29))
344
346
  c.emit("MOV", c.reg(29), c.reg(32))
347
+ // 帧分配走 SYS ALLOCFRAME (带栈溢出防护), 与 Python 编译器逐字节一致:
348
+ // 此前直接 ADDI SP 减帧长, 局部大数组会把 SP 推到负地址 (越界/静默破坏内存)。
345
349
  if c.frameBytes != 0 {
346
- c.emit("ADDI", c.reg(0), c.reg(32), c.imm(int64(-c.frameBytes)))
347
- c.emit("MOV", c.reg(32), c.reg(0))
350
+ c.emit("MOV", c.reg(0), c.imm(int64(c.frameBytes)))
351
+ c.emit("SYS", c.imm(SysALLOCFRAME))
348
352
  }
349
353
 
350
354
  // struct 局部变量: 堆分配对象
@@ -1923,6 +1927,25 @@ func (c *compiler) genCall(name string, args []*Node) *Type {
1923
1927
  c.emit("SYS", c.imm(SysATOI))
1924
1928
  return scalarT(kInt)
1925
1929
  }
1930
+ if name == "to_int" || name == "to_float" {
1931
+ // 显式类型转换: to_int 向零截断 (与 int x = 1.9 一致), to_float 提升。
1932
+ // 与 Python 编译器 (cin.py) 的同名内建语义逐一致。
1933
+ argT := c.genValue(args[0])
1934
+ target := scalarT(kInt)
1935
+ if name == "to_float" {
1936
+ target = scalarT(kFloat)
1937
+ }
1938
+ if argT == nil || (argT.Kind != kInt && argT.Kind != kFloat && argT.Kind != kBool) {
1939
+ got := "void"
1940
+ if argT != nil {
1941
+ got = typeName(argT)
1942
+ }
1943
+ c.failf("%s() expects a numeric argument, got %s", name, got)
1944
+ return nil
1945
+ }
1946
+ c.convert(argT, target)
1947
+ return target
1948
+ }
1926
1949
 
1927
1950
  // 宿主能力 (表驱动): 音频 / 画布 / 系统交互 / Termux API
1928
1951
  if hb, ok := hostBuiltins[name]; ok {
@@ -1946,6 +1969,12 @@ func (c *compiler) genCall(name string, args []*Node) *Type {
1946
1969
  // 用户函数
1947
1970
  fdef := c.functions[name]
1948
1971
  if fdef == nil {
1972
+ if name == "int" || name == "float" {
1973
+ c.failf("Unknown function: %s (hint: use to_%s(x) for explicit "+
1974
+ "conversion, or rely on implicit promotion in mixed "+
1975
+ "int/float expressions)", name, name)
1976
+ return nil
1977
+ }
1949
1978
  c.failf("Unknown function: %s", name)
1950
1979
  return nil
1951
1980
  }
@@ -141,3 +141,6 @@ const SysAUDIOPLAYING = 133
141
141
  const SysAUDIOPAUSE = 134
142
142
  const SysAUDIORESUME = 135
143
143
  const SysAUDIOLEVEL = 136
144
+ const SysALLOCFRAME = 137
145
+ const SysTIMEUS = 138
146
+ const SysTIMENS = 139
@@ -500,3 +500,6 @@ const sysAUDIOPLAYING = 133
500
500
  const sysAUDIOPAUSE = 134
501
501
  const sysAUDIORESUME = 135
502
502
  const sysAUDIOLEVEL = 136
503
+ const sysALLOCFRAME = 137
504
+ const sysTIMEUS = 138
505
+ const sysTIMENS = 139
@@ -4,4 +4,4 @@
4
4
  package engine
5
5
 
6
6
  // BuildVersion 是 Code CIN 的版本号 (被 codecin_version() 与日志使用)。
7
- const BuildVersion = "5.8.0"
7
+ const BuildVersion = "5.8.2"
@@ -50,6 +50,7 @@ type vmState struct {
50
50
  sp uint64
51
51
  pc int
52
52
  heapPtr uint64
53
+ heapBase uint64 // 堆起始 (heapPtr 初值; 报错信息用)
53
54
  steps uint64
54
55
  flags struct{ N, Z, C, V bool }
55
56
  out strings.Builder
@@ -199,15 +200,16 @@ func Run(bc []byte, mem []byte, entry, sp, heapBase int64, inData []byte,
199
200
  ent = int(entry)
200
201
  }
201
202
  vm := &vmState{
202
- prog: prog,
203
- entry: ent,
204
- mem: mem,
205
- sp: uint64(sp),
206
- pc: ent,
207
- heapPtr: uint64(heapBase),
208
- rng: rand.New(rand.NewSource(time.Now().UnixNano())),
209
- inData: inData,
210
- args: currentProgramArgs(),
203
+ prog: prog,
204
+ entry: ent,
205
+ mem: mem,
206
+ sp: uint64(sp),
207
+ pc: ent,
208
+ heapPtr: uint64(heapBase),
209
+ heapBase: uint64(heapBase),
210
+ rng: rand.New(rand.NewSource(time.Now().UnixNano())),
211
+ inData: inData,
212
+ args: currentProgramArgs(),
211
213
  }
212
214
 
213
215
  // 键盘监听可能切换终端 raw mode, 任何出口都必须恢复 (幂等)
@@ -280,7 +282,7 @@ func opcodeSupported(op uint8) bool {
280
282
  }
281
283
 
282
284
  func syscallSupported(id uint64) bool {
283
- return id <= sysAUDIOLEVEL
285
+ return id <= sysTIMENS
284
286
  }
285
287
 
286
288
  func (vm *vmState) reg(n int) uint64 {
@@ -342,7 +344,13 @@ func (vm *vmState) val(op operand) (uint64, bool) {
342
344
 
343
345
  func (vm *vmState) checkAddr(addr uint64, width int) string {
344
346
  if uint64(len(vm.mem)) < uint64(width) || addr > uint64(len(vm.mem))-uint64(width) {
345
- return "address " + strconv.FormatUint(addr, 16) + " out of bounds"
347
+ hint := ""
348
+ if addr >= 1<<63 {
349
+ // 按位模 2^64 后为负数: 典型成因是栈溢出 (SP 被推到负地址)
350
+ // 或野指针。可读性提示, 与 Python 侧 memory.py 文案一致。
351
+ hint = " (negative address: stack overflow or bad pointer?)"
352
+ }
353
+ return "Address 0x" + strconv.FormatUint(addr, 16) + " out of bounds" + hint
346
354
  }
347
355
  return ""
348
356
  }
@@ -976,7 +984,14 @@ func (vm *vmState) doSyscall(id uint64) string {
976
984
  ptr := vm.heapPtr
977
985
  vm.heapPtr += size
978
986
  if vm.heapPtr > vm.sp {
979
- return "Heap exhausted"
987
+ free := uint64(0)
988
+ if vm.sp > ptr {
989
+ free = vm.sp - ptr
990
+ }
991
+ // 文本与 Python 解释器 (cpu.py) 保持一致
992
+ return fmt.Sprintf("Heap exhausted: need %d bytes, free %d bytes "+
993
+ "(heap 0x%x..0x%x). Try --mem-size (default 65536) or "+
994
+ "reduce allocations", size, free, vm.heapBase, vm.sp)
980
995
  }
981
996
  vm.setReg(0, ptr)
982
997
  case sysPRINTFLO:
@@ -1005,7 +1020,14 @@ func (vm *vmState) doSyscall(id uint64) string {
1005
1020
  ptr := vm.heapPtr
1006
1021
  vm.heapPtr += size
1007
1022
  if vm.heapPtr > vm.sp {
1008
- return "Heap exhausted (string concat)"
1023
+ free := uint64(0)
1024
+ if vm.sp > ptr {
1025
+ free = vm.sp - ptr
1026
+ }
1027
+ return fmt.Sprintf("Heap exhausted (string concat): need %d bytes, "+
1028
+ "free %d bytes (heap 0x%x..0x%x). Try --mem-size "+
1029
+ "(default 65536) or reduce allocations",
1030
+ size, free, vm.heapBase, vm.sp)
1009
1031
  }
1010
1032
  if e := vm.checkAddr(ptr, len(data)); e != "" {
1011
1033
  return e
@@ -1313,6 +1335,28 @@ func (vm *vmState) doSyscall(id uint64) string {
1313
1335
  vm.setReg(0, vm.argAt(x0))
1314
1336
  case sysREADLINE:
1315
1337
  vm.setReg(0, vm.readLineStr())
1338
+ // 核心 VM 机制 (非宿主能力, 与 Python 解释器 cpu.py 语义逐一致)
1339
+ case sysALLOCFRAME:
1340
+ fb := x0
1341
+ guard := vm.heapPtr + 4096
1342
+ // 有符号比较: SP 绕回 (负地址) 必须判溢出, 不能先取模再比大小
1343
+ newSP := int64(vm.sp) - int64(fb)
1344
+ if newSP < int64(guard) {
1345
+ avail := int64(vm.sp) - int64(guard)
1346
+ if avail < 0 {
1347
+ avail = 0
1348
+ }
1349
+ return fmt.Sprintf("Stack overflow: frame needs %d bytes, stack "+
1350
+ "headroom only %d bytes (SP 0x%x, guard 0x%x, memory %d "+
1351
+ "bytes). Try --mem-size (default 65536) or smaller local "+
1352
+ "arrays", fb, avail, vm.sp, guard, len(vm.mem))
1353
+ }
1354
+ vm.sp = uint64(newSP)
1355
+ vm.setReg(0, vm.sp)
1356
+ case sysTIMEUS:
1357
+ vm.setReg(0, uint64(time.Now().UnixNano()/1000))
1358
+ case sysTIMENS:
1359
+ vm.setReg(0, uint64(time.Now().UnixNano()))
1316
1360
  default:
1317
1361
  return "Unknown SYS call id"
1318
1362
  }
@@ -1326,7 +1370,14 @@ func (vm *vmState) heapDupString(s string) (uint64, string) {
1326
1370
  ptr := vm.heapPtr
1327
1371
  vm.heapPtr += size
1328
1372
  if vm.heapPtr > vm.sp {
1329
- return 0, "Heap exhausted (string operation)"
1373
+ free := uint64(0)
1374
+ if vm.sp > ptr {
1375
+ free = vm.sp - ptr
1376
+ }
1377
+ return 0, fmt.Sprintf("Heap exhausted (string operation): need %d "+
1378
+ "bytes, free %d bytes (heap 0x%x..0x%x). Try --mem-size "+
1379
+ "(default 65536) or reduce allocations",
1380
+ size, free, vm.heapBase, vm.sp)
1330
1381
  }
1331
1382
  if e := vm.checkAddr(ptr, len(data)); e != "" {
1332
1383
  return 0, e
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecin
3
- Version: 5.8.0
3
+ Version: 5.8.2
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
@@ -175,6 +175,7 @@ tests/test_gui.py
175
175
  tests/test_index_subscript_type.py
176
176
  tests/test_isa_dispatch.py
177
177
  tests/test_isa_single_source.py
178
+ tests/test_issue_regress.py
178
179
  tests/test_keyboard.py
179
180
  tests/test_lib_bigint.py
180
181
  tests/test_lib_bitset.py
@@ -1,8 +1,8 @@
1
1
  // Code CIN 命令行参数与行输入演示 (SYS 129..131, 跨平台一致)
2
- // 运行: codecin examples/args_demo.cin -- alice 42
3
- // codecin examples/args_demo.cin -- alice 42
4
- // 参数在 `--` 之后传给 CIN 程序; AOT 产物直接取进程 os.Args[1:]。
5
- // 另见 stdlib: gostd.cin 的 go_os_args_len() / go_os_args_get(i)。
2
+ // 运行: codecin examples/args_demo.cin alice 42 (程序名后直传)
3
+ // codecin examples/args_demo.cin -- alice 42 (`--` 显式分隔, 兼容旧法)
4
+ // 两种方式等价; 含 `--` 前缀形如选项的参数必须走 `--`。AOT 产物直接取进程
5
+ // os.Args[1:]。另见 stdlib: gostd.cin 的 go_os_args_len() / go_os_args_get(i)。
6
6
 
7
7
  function main() -> int {
8
8
  int n = arg_count()