基本稳定
This commit is contained in:
1 parent
0a10b20dde
commit
a39b5da0f8
27 files changed
+392
-962
No files matched your search
@@ -1 +0,0 @@
|
||||
{"D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\Projectrans\\Config.vp": {"sha1": "c0042adc0b7ec5df", "mtime": 1785332415.2264168, "size": 14060}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\Projectrans\\Utils.vp": {"sha1": "4650533467115342", "mtime": 1785332415.2054548, "size": 4900}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\StubGen\\Converter.vp": {"sha1": "edfb76eb5b11cb51", "mtime": 1785470008.8908188, "size": 36399}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\StubGen\\VpiReader.vp": {"sha1": "3395dd5ebf7032b7", "mtime": 1785688467.8441546, "size": 21045}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\__init__.vp": {"sha1": "c2a4277744568003", "mtime": 1785424554.7031634, "size": 820}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\BuildPipeline.vp": {"sha1": "0029b86ca4ba3c8a", "mtime": 1785469972.0876107, "size": 25400}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesAnnAssign.vp": {"sha1": "b7705a803012e701", "mtime": 1785478290.7112954, "size": 25035}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesAssign.vp": {"sha1": "4614c82057c20ce0", "mtime": 1785612002.0288458, "size": 26204}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesAugAssign.vp": {"sha1": "0d60272ffec7421e", "mtime": 1785478333.5054357, "size": 14418}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesBase.vp": {"sha1": "63a3d17e96a083ac", "mtime": 1785332415.2080498, "size": 8740}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesBody.vp": {"sha1": "144543e5c3a8e884", "mtime": 1785500799.3788817, "size": 10543}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesClassDef.vp": {"sha1": "22b233500a91b82a", "mtime": 1785688461.7589297, "size": 147577}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesEnum.vp": {"sha1": "d8379d695f0ce7ea", "mtime": 1785598131.284988, "size": 8533}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesExpr.vp": {"sha1": "ebe9603dbffb6a35", "mtime": 1785478439.6070976, "size": 155333}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesExprCall.vp": {"sha1": "1d86dddccc01909b", "mtime": 1785688462.1500714, "size": 296707}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesExprOps.vp": {"sha1": "ede39cea216a347e", "mtime": 1785478524.0725746, "size": 13507}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesFor.vp": {"sha1": "456fb516ba3c5002", "mtime": 1785332415.1896677, "size": 17319}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesFunctions.vp": {"sha1": "f33eba0679c883b5", "mtime": 1785580039.9426627, "size": 49481}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesIf.vp": {"sha1": "f4cdbca2f8802c12", "mtime": 1785390159.3673935, "size": 5626}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesImports.vp": {"sha1": "c34e22cc668c6a6e", "mtime": 1785424554.7057025, "size": 25292}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesMain.vp": {"sha1": "4a7b57e6bd18f65e", "mtime": 1785332415.1935978, "size": 21362}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesMatch.vp": {"sha1": "4eb645a9b00ea530", "mtime": 1785688462.3238158, "size": 39328}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesNonlocal.vp": {"sha1": "3e7835a9deb60427", "mtime": 1785485362.3779018, "size": 7459}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesReturn.vp": {"sha1": "9224f6a9c894a6cf", "mtime": 1785478537.512802, "size": 6346}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesStruct.vp": {"sha1": "d539c830f47d8334", "mtime": 1785688462.3561263, "size": 48050}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesTranslator.vp": {"sha1": "d064df0bb07fe1ff", "mtime": 1785688462.4070482, "size": 24182}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesType.vp": {"sha1": "6a25d9b413498b72", "mtime": 1785608629.9467041, "size": 80761}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesVar.vp": {"sha1": "ea374464a0b93230", "mtime": 1785474869.3558953, "size": 16575}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesWhile.vp": {"sha1": "8dc65d4c71e2936a", "mtime": 1785390170.5239043, "size": 5202}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\IncludesScanner.vp": {"sha1": "55be14b41dd7ca15",Line truncated
|
||||
@@ -1,82 +0,0 @@
|
||||
0029b86ca4ba3c8a:lib/core/BuildPipeline.vp
|
||||
067c78e9f121dce3:includes/w32\win32process.vp
|
||||
06f53cc594b4ac6c:includes/w32\win32sync.vp
|
||||
0bae3da2213d51e9:lib/core/StubMerger.vp
|
||||
0c67644125bea0fd:includes/sys.vp
|
||||
0d60272ffec7421e:lib/core/Handles/HandlesAugAssign.vp
|
||||
0df65b8ed15664b0:includes/hashlib\__sha1.vp
|
||||
144543e5c3a8e884:lib/core/Handles/HandlesBody.vp
|
||||
19f8024d10c828e8:includes/hashlib\__md5.vp
|
||||
1d86dddccc01909b:lib/core/Handles/HandlesExprCall.vp
|
||||
20cd49775c100a38:includes/json\__writer.vp
|
||||
22b233500a91b82a:lib/core/Handles/HandlesClassDef.vp
|
||||
22bc0df83b3f0e62:includes/ast\base.vp
|
||||
240a9a4157959a9f:includes/json\__parser.vp
|
||||
285b6aa29a34754d:includes/stdio.vp
|
||||
28de517e3820658a:includes/posix.vp
|
||||
295b7ed2c244f309:includes/llvmlite\__types.vp
|
||||
2b77d783c41d21d1:includes/hashtable.vp
|
||||
3395dd5ebf7032b7:lib/StubGen/VpiReader.vp
|
||||
33d64eeb99369a85:includes/llvmlite\__init__.vp
|
||||
3aa6057398be5673:includes/stdlib.vp
|
||||
3e7835a9deb60427:lib/core/Handles/HandlesNonlocal.vp
|
||||
4337fb260448bbe2:includes/ast\astaux.vp
|
||||
456fb516ba3c5002:lib/core/Handles/HandlesFor.vp
|
||||
4614c82057c20ce0:lib/core/Handles/HandlesAssign.vp
|
||||
4650533467115342:lib/Projectrans/Utils.vp
|
||||
4a7b57e6bd18f65e:lib/core/Handles/HandlesMain.vp
|
||||
4dd6b3f1427d1cc5:includes/ast\match.vp
|
||||
4eb645a9b00ea530:lib/core/Handles/HandlesMatch.vp
|
||||
55be14b41dd7ca15:lib/core/IncludesScanner.vp
|
||||
63a3d17e96a083ac:lib/core/Handles/HandlesBase.vp
|
||||
657e182b27c2a022:includes/ast\stmts.vp
|
||||
692919c5a194ac8d:includes/llvmlite\__module.vp
|
||||
6a25d9b413498b72:lib/core/Handles/HandlesType.vp
|
||||
6b3bc463fd044545:includes/llvmlite\__verify.vp
|
||||
6ddf430432a0e373:includes/json\__init__.vp
|
||||
6ff26590374ae6fc:includes/hashlib\__sha512.vp
|
||||
71e0a3ffcb3ebfad:includes/stdarg.vp
|
||||
72dbbb563aa943b0:includes/w32\fileio.vp
|
||||
7cadfe07e983fd90:includes/_list.vp
|
||||
874bac141c97bae9:includes/llvmlite\__function.vp
|
||||
8a526c65749808c5:lib/core/Phase1.vp
|
||||
8dc65d4c71e2936a:lib/core/Handles/HandlesWhile.vp
|
||||
9224f6a9c894a6cf:lib/core/Handles/HandlesReturn.vp
|
||||
96837bcc64032444:includes/hashlib\__init__.vp
|
||||
a335eb99f2e34479:includes/subprocess.vp
|
||||
a5e9a83e9db303ad:includes/linkedlist.vp
|
||||
a6c58174a4b03877:main.vp
|
||||
a7748ef067f79205:includes/llvmlite\__builder.vp
|
||||
aa246c6e6aa30484:includes/atom.vp
|
||||
b370d93b74bf55cc:includes/argparse.vp
|
||||
b543bc1dfb592119:includes/ast\exprs.vp
|
||||
b547ac4f380bddb6:includes/ast\tokens.vp
|
||||
b57252077e6b596b:includes/platmacro.vp
|
||||
b7705a803012e701:lib/core/Handles/HandlesAnnAssign.vp
|
||||
bbdf3bbd4c3bc28c:includes/w32\win32console.vp
|
||||
bdf5730851fb95f2:lib/core/VLogger.vp
|
||||
c0042adc0b7ec5df:lib/Projectrans/Config.vp
|
||||
c2a4277744568003:lib/__init__.vp
|
||||
c2d8b39bbdb8380a:includes/memhub.vp
|
||||
c34e22cc668c6a6e:lib/core/Handles/HandlesImports.vp
|
||||
c9d54a4158f7f5a8:includes/hashlib\__sha256.vp
|
||||
c9f4be41ca1cc2b4:includes/viperio.vp
|
||||
d064df0bb07fe1ff:lib/core/Handles/HandlesTranslator.vp
|
||||
d539c830f47d8334:lib/core/Handles/HandlesStruct.vp
|
||||
d8379d695f0ce7ea:lib/core/Handles/HandlesEnum.vp
|
||||
e217def267d3d4a8:includes/ast\lexer.vp
|
||||
ea374464a0b93230:lib/core/Handles/HandlesVar.vp
|
||||
ebe9603dbffb6a35:lib/core/Handles/HandlesExpr.vp
|
||||
ede39cea216a347e:lib/core/Handles/HandlesExprOps.vp
|
||||
edfb76eb5b11cb51:lib/StubGen/Converter.vp
|
||||
f33eba0679c883b5:lib/core/Handles/HandlesFunctions.vp
|
||||
f34071b7cf6c8158:lib/core/Phase2.vp
|
||||
f3444ec56937284f:includes/ast\__init__.vp
|
||||
f4cdbca2f8802c12:lib/core/Handles/HandlesIf.vp
|
||||
f5522571bcce7bcb:includes/stdint.vp
|
||||
f6ab8989f3545e83:includes/viperlib.vp
|
||||
f6b51804a0ba8ff0:includes/w32\win32file.vp
|
||||
f9e36e2cd6fa659f:includes/llvmlite\__values.vp
|
||||
fc980acec33d69a7:includes/w32\win32base.vp
|
||||
fde6db0747bdd959:includes/ast\parser.vp
|
||||
ffaf70367668b227:includes/string.vp
|
||||
Binary file not shown.
@@ -1,84 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pathlib
|
||||
|
||||
# 1. VpiReader.vp
|
||||
p = pathlib.Path(r'd:\Users\TermiNexus\Desktop\TransPyC\TransPyV\App\lib\StubGen\VpiReader.vp')
|
||||
c = p.read_text(encoding='utf-8')
|
||||
lines = c.split('\n')
|
||||
new_lines = []
|
||||
skip = False
|
||||
for i, line in enumerate(lines):
|
||||
if 'DEBUG: sha1_buf length mismatch' in line:
|
||||
skip = True
|
||||
# also skip preceding lines
|
||||
while new_lines and ('_buflen' in new_lines[-1] or 'sha1_buf' in new_lines[-1] or len(new_lines[-1].strip()) == 0 or new_lines[-1].strip().startswith('#')):
|
||||
new_lines.pop()
|
||||
continue
|
||||
if skip:
|
||||
if 'sys.exit(1)' in line:
|
||||
skip = False
|
||||
continue
|
||||
if 'stdio.' in line or '_buflen' in line:
|
||||
continue
|
||||
if line.strip() == '' or line.strip().startswith('if _buflen'):
|
||||
continue
|
||||
skip = False
|
||||
new_lines.append(line)
|
||||
p.write_text('\n'.join(new_lines), encoding='utf-8')
|
||||
print('VpiReader.vp done')
|
||||
|
||||
# 2. HandlesFunctions.vp
|
||||
p2 = pathlib.Path(r'd:\Users\TermiNexus\Desktop\TransPyC\TransPyV\App\lib\core\Handles\HandlesFunctions.vp')
|
||||
c2 = p2.read_text(encoding='utf-8')
|
||||
lines2 = c2.split('\n')
|
||||
new_lines2 = []
|
||||
skip2 = False
|
||||
for line in lines2:
|
||||
if 'DEBUG: double-dot in _mangle_name' in line:
|
||||
skip2 = True
|
||||
while new_lines2 and ('_mi' in new_lines2[-1] or 'mangled[_mi' in new_lines2[-1] or 'stdio.' in new_lines2[-1] or 'sys.exit' in new_lines2[-1] or new_lines2[-1].strip().startswith('#')):
|
||||
new_lines2.pop()
|
||||
continue
|
||||
if skip2:
|
||||
if 'sys.exit(1)' in line:
|
||||
skip2 = False
|
||||
continue
|
||||
if 'stdio.' in line or '_mi' in line or 'mangled[_mi' in line or line.strip().startswith('if mangled'):
|
||||
continue
|
||||
if line.strip() == '' or line.strip() == 'return mangled':
|
||||
if line.strip() == 'return mangled':
|
||||
new_lines2.append(line)
|
||||
skip2 = False
|
||||
continue
|
||||
skip2 = False
|
||||
new_lines2.append(line)
|
||||
p2.write_text('\n'.join(new_lines2), encoding='utf-8')
|
||||
print('HandlesFunctions.vp done')
|
||||
|
||||
# 3. HandlesExprCall.vp
|
||||
p3 = pathlib.Path(r'd:\Users\TermiNexus\Desktop\TransPyC\TransPyV\App\lib\core\Handles\HandlesExprCall.vp')
|
||||
c3 = p3.read_text(encoding='utf-8')
|
||||
lines3 = c3.split('\n')
|
||||
new_lines3 = []
|
||||
skip3 = False
|
||||
for line in lines3:
|
||||
if 'DEBUG: double-dot in call_name' in line:
|
||||
skip3 = True
|
||||
while new_lines3 and ('_cni' in new_lines3[-1] or 'call_name[_cni' in new_lines3[-1] or 'stdio.' in new_lines3[-1] or 'sys.exit' in new_lines3[-1] or new_lines3[-1].strip().startswith('#')):
|
||||
new_lines3.pop()
|
||||
continue
|
||||
if skip3:
|
||||
if 'sys.exit(1)' in line:
|
||||
skip3 = False
|
||||
continue
|
||||
if 'stdio.' in line or '_cni' in line or 'call_name[_cni' in line or line.strip().startswith('if call_name'):
|
||||
continue
|
||||
if line.strip() == '' or line.strip().startswith('#'):
|
||||
if line.strip().startswith('#'):
|
||||
new_lines3.append(line)
|
||||
skip3 = False
|
||||
continue
|
||||
skip3 = False
|
||||
new_lines3.append(line)
|
||||
p3.write_text('\n'.join(new_lines3), encoding='utf-8')
|
||||
print('HandlesExprCall.vp done')
|
||||
-197
@@ -1,197 +0,0 @@
|
||||
import tkinter as tk
|
||||
from tkinter import scrolledtext
|
||||
import subprocess
|
||||
import threading
|
||||
import sys
|
||||
import os
|
||||
import queue
|
||||
import time
|
||||
|
||||
|
||||
|
||||
class ConsoleApp:
|
||||
def __init__(self, root, args):
|
||||
self.root = root
|
||||
self.args = args
|
||||
self.proc = None
|
||||
self.output_queue = queue.Queue()
|
||||
|
||||
# 获取系统当前编码,尽量保证原样输出
|
||||
self.encoding = sys.stdout.encoding or 'utf-8'
|
||||
|
||||
# 记录最后一次收到输出的时间
|
||||
self.last_output_time = time.time()
|
||||
|
||||
root.title("AI 交互终端")
|
||||
root.geometry("900x600")
|
||||
|
||||
# GUI 布局
|
||||
# 输出区域
|
||||
self.text_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, font=("Consolas", 10))
|
||||
self.text_area.pack(expand=True, fill='both', padx=5, pady=5)
|
||||
|
||||
# 输入区域
|
||||
input_frame = tk.Frame(root)
|
||||
input_frame.pack(fill='x', padx=5, pady=5)
|
||||
|
||||
self.entry = tk.Entry(input_frame, font=("Consolas", 10))
|
||||
self.entry.pack(side=tk.LEFT, expand=True, fill='x')
|
||||
self.entry.bind('<Return>', self.send_input)
|
||||
|
||||
# 说话模式复选框
|
||||
self.speak_mode = tk.BooleanVar(value=False)
|
||||
self.speak_check = tk.Checkbutton(input_frame, text="提示AI(说话)", variable=self.speak_mode, font=("Consolas", 9))
|
||||
self.speak_check.pack(side=tk.RIGHT, padx=5)
|
||||
|
||||
self.kill_btn = tk.Button(input_frame, text="强制终止进程", command=self.force_terminate, bg="red", fg="white")
|
||||
self.kill_btn.pack(side=tk.RIGHT, padx=5)
|
||||
|
||||
# 状态栏 (用于显示无输出时长)
|
||||
status_frame = tk.Frame(root)
|
||||
status_frame.pack(fill='x', padx=5, pady=(0, 5))
|
||||
self.time_label = tk.Label(status_frame, text="无输出时长: 00:00", font=("Consolas", 10), fg="gray")
|
||||
self.time_label.pack(side=tk.RIGHT)
|
||||
|
||||
# 启动子进程 (合并 stderr 到 stdout)
|
||||
try:
|
||||
self.proc = subprocess.Popen(
|
||||
self.args,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
bufsize=0 # 无缓冲,确保实时性
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"启动进程失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 启动读取子进程输出的线程
|
||||
self.output_thread = threading.Thread(target=self.read_output, daemon=True)
|
||||
self.output_thread.start()
|
||||
|
||||
# 启动读取当前脚本控制台输入的线程 (允许直接在终端输入)
|
||||
self.stdin_thread = threading.Thread(target=self.read_stdin, daemon=True)
|
||||
self.stdin_thread.start()
|
||||
|
||||
# 窗口关闭事件
|
||||
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
|
||||
# 开始轮询队列更新GUI
|
||||
self.update_gui()
|
||||
|
||||
def read_output(self):
|
||||
"""后台线程:实时读取子进程的输出"""
|
||||
fd = self.proc.stdout.fileno()
|
||||
while True:
|
||||
try:
|
||||
byte_data = os.read(fd, 1024)
|
||||
if not byte_data:
|
||||
break # 进程结束
|
||||
|
||||
# 只要收到数据,就更新最后输出时间
|
||||
self.last_output_time = time.time()
|
||||
|
||||
# 1. 实时输出到当前脚本的 stdout (不加任何前缀)
|
||||
sys.stdout.buffer.write(byte_data)
|
||||
sys.stdout.buffer.flush()
|
||||
|
||||
# 2. 放入队列供 GUI 使用
|
||||
try:
|
||||
text = byte_data.decode(self.encoding, errors='replace')
|
||||
except:
|
||||
text = byte_data.decode('utf-8', errors='replace')
|
||||
self.output_queue.put(text)
|
||||
except OSError:
|
||||
break # 管道已关闭
|
||||
|
||||
def read_stdin(self):
|
||||
"""后台线程:实时读取宿主控制台的 stdin 并转发给子进程"""
|
||||
while True:
|
||||
line = sys.stdin.readline()
|
||||
if not line:
|
||||
break
|
||||
try:
|
||||
self.proc.stdin.write(line.encode(self.encoding, errors='replace'))
|
||||
self.proc.stdin.flush()
|
||||
except:
|
||||
break
|
||||
|
||||
def send_input(self, event):
|
||||
"""GUI 输入框回车事件"""
|
||||
text = self.entry.get()
|
||||
self.entry.delete(0, tk.END)
|
||||
if not text:
|
||||
return
|
||||
|
||||
# 如果勾选了"提示AI",则直接输出到当前脚本的 stdout,不发给子进程
|
||||
if self.speak_mode.get():
|
||||
speak_text = text + '\n'
|
||||
# 输出到当前脚本控制台,供 AI 捕获
|
||||
sys.stdout.buffer.write(speak_text.encode(self.encoding, errors='replace'))
|
||||
sys.stdout.buffer.flush()
|
||||
|
||||
# 在 GUI 中回显,让用户知道说了什么(使用不同颜色区分)
|
||||
self.text_area.insert(tk.END, speak_text, 'speak_tag')
|
||||
self.text_area.tag_config('speak_tag', foreground="blue")
|
||||
self.text_area.see(tk.END)
|
||||
else:
|
||||
# 正常模式:发给子进程
|
||||
text += '\n'
|
||||
try:
|
||||
self.proc.stdin.write(text.encode(self.encoding, errors='replace'))
|
||||
self.proc.stdin.flush()
|
||||
except Exception as e:
|
||||
self.output_queue.put(f"\n[输入发送失败: {e}]\n")
|
||||
|
||||
def force_terminate(self):
|
||||
"""强制终止子进程"""
|
||||
if self.proc and self.proc.poll() is None:
|
||||
print("用户终止了应用程序") # 输出到控制台 stdout
|
||||
self.output_queue.put("\n[用户终止了应用程序]\n")
|
||||
self.proc.kill()
|
||||
|
||||
def on_closing(self):
|
||||
"""关闭窗口时终止子进程"""
|
||||
if self.proc and self.proc.poll() is None:
|
||||
self.proc.kill()
|
||||
self.root.destroy()
|
||||
|
||||
def update_gui(self):
|
||||
"""主线程:从队列获取数据并更新GUI"""
|
||||
try:
|
||||
while True:
|
||||
text = self.output_queue.get_nowait()
|
||||
self.text_area.insert(tk.END, text)
|
||||
self.text_area.see(tk.END)
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
# 计算并更新无输出时长
|
||||
if self.proc and self.proc.poll() is None:
|
||||
idle_seconds = int(time.time() - self.last_output_time)
|
||||
mins = idle_seconds // 60
|
||||
secs = idle_seconds % 60
|
||||
self.time_label.config(text=f"无输出时长: {mins:02d}:{secs:02d}")
|
||||
else:
|
||||
self.time_label.config(text="进程已结束")
|
||||
|
||||
# 检查进程是否已结束
|
||||
if self.proc and self.proc.poll() is not None:
|
||||
if self.output_queue.empty():
|
||||
self.kill_btn.config(state=tk.DISABLED, bg="grey", text="进程已结束")
|
||||
# 进程结束且输出已读取完毕,自动关闭程序
|
||||
self.root.destroy()
|
||||
return # 停止轮询
|
||||
|
||||
# 每 200ms 轮询一次 (减少CPU占用,时间显示不需要50ms那么频繁)
|
||||
self.root.after(200, self.update_gui)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("用法: python ai_console.py <command> [args...]")
|
||||
print("示例: python ai_console.py cmd")
|
||||
sys.exit(1)
|
||||
|
||||
root = tk.Tk()
|
||||
app = ConsoleApp(root, sys.argv[1:])
|
||||
root.mainloop()
|
||||
@@ -17,7 +17,7 @@ from .base import (
|
||||
_init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list,
|
||||
_binop_from_op, _augop_from_op, _cmpop_from_op,
|
||||
_emit, _emit_str, _emit_int, _dump_list,
|
||||
dump,
|
||||
dump, _op_name,
|
||||
)
|
||||
# 语句节点
|
||||
from .stmts import (
|
||||
|
||||
@@ -553,6 +553,14 @@ def _read_string(lx: Lexer | t.CPtr):
|
||||
conv_buf[wpos] = '\t'
|
||||
elif next_ch == 'r':
|
||||
conv_buf[wpos] = '\r'
|
||||
elif next_ch == 'f':
|
||||
conv_buf[wpos] = '\f'
|
||||
elif next_ch == 'v':
|
||||
conv_buf[wpos] = '\v'
|
||||
elif next_ch == 'a':
|
||||
conv_buf[wpos] = '\a'
|
||||
elif next_ch == 'b':
|
||||
conv_buf[wpos] = '\b'
|
||||
elif next_ch == '\\':
|
||||
conv_buf[wpos] = '\\'
|
||||
elif next_ch == '\'':
|
||||
|
||||
@@ -154,7 +154,7 @@ def a2b_hex(hexstr: str, length: t.CInt) -> str:
|
||||
out[oi] = '\0'
|
||||
return out
|
||||
|
||||
def unhexlify(data: str, length: t.CInt):
|
||||
def unhexlify(data: str, length: t.CInt) -> bytes:
|
||||
return a2b_hex(data, length)
|
||||
|
||||
def b2a_base64(data: str, length: t.CInt) -> str:
|
||||
|
||||
@@ -504,10 +504,10 @@ def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
_append_cstr(buf, size, "global ")
|
||||
|
||||
# 类型
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, gv.Ty, pool)
|
||||
TypePrint(ty_buf, 512, gv.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
|
||||
# 初始化值
|
||||
@@ -541,10 +541,10 @@ def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
_append_cstr(buf, size, " = external global ")
|
||||
|
||||
# 类型
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
TypePrint(ty_buf, 128, gv.Ty, pool)
|
||||
TypePrint(ty_buf, 512, gv.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import viperlib
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
import stdlib
|
||||
from linkedlist import GSListNode
|
||||
|
||||
|
||||
@@ -383,8 +384,23 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
|
||||
pool 用于递归打印子类型时分配临时缓冲区。
|
||||
"""
|
||||
_TypePrintDepth(buf, size, ty, pool, 0)
|
||||
|
||||
|
||||
# 递归深度上限:悬空/自引用的 LLVMType 树(1b reset 后内存被复用)会导致
|
||||
# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲
|
||||
# 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。
|
||||
TYPEPRINT_MAX_DEPTH: t.CDefine = 100
|
||||
|
||||
def _TypePrintDepth(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
depth: t.CInt):
|
||||
"""带递归深度上限的 TypePrint 内部实现"""
|
||||
if ty is None or buf is None or size == 0:
|
||||
return
|
||||
if depth >= TYPEPRINT_MAX_DEPTH:
|
||||
viperlib.snprintf(buf, size, "...")
|
||||
return
|
||||
buf[0] = '\0'
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
@@ -400,7 +416,10 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
match pointee:
|
||||
case LLVMType.Struct(sfields, sfcount, sname):
|
||||
if sname is not None:
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"*", sname)
|
||||
# 悬空防护:sname 可能指向被 reset 回收/部分复用的 pool 内存,
|
||||
# 用受限打印避免读越界崩溃;完整名在 vtable 生成后由
|
||||
# TypeStr 兜底(stdlib 深拷贝,跨 reset 存活)
|
||||
viperlib.snprintf(buf, size, "%%\"%.40s\"*", sname)
|
||||
return
|
||||
case LLVMType.Void():
|
||||
# Ptr(Void) → i8*(LLVM IR void* 非法)
|
||||
@@ -419,7 +438,7 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
string.strcpy(buf, "i8*")
|
||||
return
|
||||
# 通用路径: 递归打印 pointee 后追加 '*'
|
||||
TypePrint(buf, size, pointee, pool)
|
||||
_TypePrintDepth(buf, size, pointee, pool, depth + 1)
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 1 < size:
|
||||
buf[pos] = '*'
|
||||
@@ -431,7 +450,7 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
# 嵌套指针/数组更易超过 128,使用 512 字节避免截断
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 512, elem_ty, pool)
|
||||
_TypePrintDepth(tmp, 512, elem_ty, pool, depth + 1)
|
||||
_strappend(buf, size, tmp)
|
||||
_strappend(buf, size, "]")
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
@@ -440,20 +459,26 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"", name)
|
||||
else:
|
||||
# 匿名结构体: {ty1, ty2, ...}
|
||||
_print_struct_body(buf, size, fields, pool)
|
||||
_print_struct_body(buf, size, fields, pool, depth)
|
||||
case LLVMType.Func(ret, params, count):
|
||||
# ret (ty1, ty2, ...)
|
||||
TypePrint(buf, size, ret, pool)
|
||||
_TypePrintDepth(buf, size, ret, pool, depth + 1)
|
||||
_strappend(buf, size, " (")
|
||||
cur2: ParamNode | t.CPtr = params
|
||||
first2: t.CInt = 1
|
||||
_pc2: t.CInt = 0
|
||||
# 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断
|
||||
tmp3: t.CChar | t.CPtr = pool.alloc(512)
|
||||
while cur2 is not None:
|
||||
# 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环
|
||||
_pc2 += 1
|
||||
if _pc2 > 200:
|
||||
_strappend(buf, size, "...)")
|
||||
break
|
||||
if first2 == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp3 is not None:
|
||||
TypePrint(tmp3, 512, cur2.Ty, pool)
|
||||
_TypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1)
|
||||
_strappend(buf, size, tmp3)
|
||||
cur2 = cur2.Next
|
||||
first2 = 0
|
||||
@@ -502,7 +527,8 @@ def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr)
|
||||
# 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用
|
||||
# ============================================================
|
||||
def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
depth: t.CInt = 0):
|
||||
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)
|
||||
|
||||
直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存
|
||||
@@ -515,13 +541,18 @@ def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
first: t.CInt = 1
|
||||
fidx: t.CInt = 0
|
||||
while cur is not None:
|
||||
# 悬空保护:ParamNode 链若被 reset 回收后内容复用,Next 指针可能成环或
|
||||
# 指向垃圾,无限循环。最多打印 200 个字段即停止,防止 OOM。
|
||||
if fidx >= 200:
|
||||
_strappend(buf, size, "...}")
|
||||
return
|
||||
if first == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
# 直接在 buf 当前末尾位置写入字段类型
|
||||
# TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0')
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 2 < size:
|
||||
TypePrint(buf + pos, size - pos, cur.Ty, pool)
|
||||
_TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
fidx += 1
|
||||
@@ -574,4 +605,144 @@ def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
|
||||
return None
|
||||
|
||||
|
||||
def get_struct_fields(ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
|
||||
"""获取结构体的字段链表(供跨模块重建 Struct 类型用)"""
|
||||
if ty is None:
|
||||
return None
|
||||
match ty:
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
return fields
|
||||
case _:
|
||||
return None
|
||||
|
||||
|
||||
def get_struct_fcount(ty: LLVMType | t.CPtr) -> t.CInt:
|
||||
"""获取结构体的字段数量(供跨模块重建 Struct 类型用)"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
return fcount
|
||||
case _:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活)
|
||||
#
|
||||
# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其
|
||||
# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1)
|
||||
# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历
|
||||
# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空
|
||||
# 指针导致崩溃(0xC0000005)。
|
||||
#
|
||||
# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和
|
||||
# 字符串名),保证 entry.Ty 跨文件永久存活。
|
||||
#
|
||||
# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归,
|
||||
# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。
|
||||
# ============================================================
|
||||
DEEPCOPY_MAX_DEPTH: t.CDefine = 64
|
||||
|
||||
def DeepCopyType(pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
|
||||
"""深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None"""
|
||||
return _DeepCopyDepth(pool, ty, 0)
|
||||
|
||||
|
||||
def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr:
|
||||
"""带深度上限的深拷贝实现"""
|
||||
if ty is None:
|
||||
return None
|
||||
new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(stdlib.malloc(LLVMType.__sizeof__()))
|
||||
if new_ty is None:
|
||||
return None
|
||||
string.memset(new_ty, 0, LLVMType.__sizeof__())
|
||||
if depth >= DEEPCOPY_MAX_DEPTH:
|
||||
# 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型)
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Int(bits))
|
||||
case LLVMType.Float(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Float(bits))
|
||||
case LLVMType.Void():
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
case LLVMType.Label():
|
||||
c.DerefAs(new_ty, LLVMType.Label())
|
||||
case LLVMType.Metadata():
|
||||
c.DerefAs(new_ty, LLVMType.Metadata())
|
||||
case _:
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
return new_ty
|
||||
match ty:
|
||||
case LLVMType.Int(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Int(bits))
|
||||
case LLVMType.Float(bits):
|
||||
c.DerefAs(new_ty, LLVMType.Float(bits))
|
||||
case LLVMType.Void():
|
||||
c.DerefAs(new_ty, LLVMType.Void())
|
||||
case LLVMType.Label():
|
||||
c.DerefAs(new_ty, LLVMType.Label())
|
||||
case LLVMType.Metadata():
|
||||
c.DerefAs(new_ty, LLVMType.Metadata())
|
||||
case LLVMType.Ptr(pointee):
|
||||
c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1)))
|
||||
case LLVMType.Array(elem_ty, count):
|
||||
c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count))
|
||||
case LLVMType.Func(ret, params, pcount):
|
||||
c.DerefAs(new_ty, LLVMType.Func(
|
||||
_DeepCopyDepth(pool, ret, depth + 1),
|
||||
_DeepCopyParamChain(pool, params, depth + 1), pcount))
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
c.DerefAs(new_ty, LLVMType.Struct(
|
||||
_DeepCopyParamChain(pool, fields, depth + 1),
|
||||
fcount, _DeepCopyStr(pool, name)))
|
||||
case _:
|
||||
stdlib.free(new_ty)
|
||||
return None
|
||||
return new_ty
|
||||
|
||||
|
||||
def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr,
|
||||
head: ParamNode | t.CPtr, depth: t.CInt) -> ParamNode | t.CPtr:
|
||||
"""深拷贝 ParamNode 链表到 stdlib"""
|
||||
if head is None:
|
||||
return None
|
||||
first: ParamNode | t.CPtr = None
|
||||
prev: ParamNode | t.CPtr = None
|
||||
cur: ParamNode | t.CPtr = head
|
||||
guard: t.CInt = 0
|
||||
while cur is not None:
|
||||
guard += 1
|
||||
if guard > 512:
|
||||
break
|
||||
node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(stdlib.malloc(PNODE_SIZE))
|
||||
if node is None:
|
||||
break
|
||||
string.memset(node, 0, PNODE_SIZE)
|
||||
node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1)
|
||||
node.Next = None
|
||||
if first is None:
|
||||
first = node
|
||||
if prev is not None:
|
||||
prev.Next = node
|
||||
prev = node
|
||||
cur = paramnode_get_next(cur)
|
||||
return first
|
||||
|
||||
|
||||
def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
|
||||
"""深拷贝字符串到 stdlib"""
|
||||
if s is None:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(s)
|
||||
copy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
|
||||
if copy is None:
|
||||
return None
|
||||
string.strcpy(copy, s)
|
||||
return copy
|
||||
|
||||
|
||||
|
||||
|
||||
+116
-6
@@ -4,7 +4,7 @@ import string
|
||||
import atom
|
||||
import viperio
|
||||
import stdio
|
||||
import sys
|
||||
import stdlib
|
||||
|
||||
# ============================================================
|
||||
# memhub - Unified memory management library
|
||||
@@ -26,7 +26,6 @@ MEMBUDDY_MIN_BLOCK: t.CDefine = 32
|
||||
MEMBUDDY_MAX_ORDERS: t.CDefine = 32
|
||||
MEMBUDDY_HEADER_SIZE: t.CDefine = 8
|
||||
|
||||
|
||||
def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT:
|
||||
if align == 0: return val
|
||||
return (val + align - 1) & ~(align - 1)
|
||||
@@ -134,7 +133,13 @@ class MemPool(MemManager):
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
if size == 0: return None
|
||||
aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN)
|
||||
if self.offset + aligned > self.size: return None
|
||||
if self.offset + aligned > self.size:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size)
|
||||
stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n",
|
||||
self.size, self.offset)
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
stdlib.exit(1)
|
||||
ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.base) + self.offset, t.CPtr)
|
||||
self.offset += aligned
|
||||
if self.offset > self.high_water:
|
||||
@@ -211,8 +216,18 @@ class MemSlab(MemManager):
|
||||
|
||||
def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr:
|
||||
# Slab mode: allocate one block only if requested size <= block_size
|
||||
if self.free_list is None: return None
|
||||
if size > self.block_size: return None
|
||||
if self.free_list is None:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败(free_list 已空)\n", size)
|
||||
stdio.printf("[OOM] MemSlab: block_size=%zu block_count=%zu used=%zu\n",
|
||||
self.block_size, self.block_count, self.used_count)
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
stdlib.exit(1)
|
||||
if size > self.block_size:
|
||||
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
|
||||
stdio.printf("[OOM] 尝试分配: %zu 字节,失败(超过 block_size=%zu)\n", size, self.block_size)
|
||||
stdio.printf("[OOM] 说明: 请求大小超过 MemSlab 块大小,应改用 MemBuddy/MemPool。\n")
|
||||
stdlib.exit(1)
|
||||
block: t.CVoid | t.CPtr = self.free_list
|
||||
self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
|
||||
self.used_count += 1
|
||||
@@ -254,6 +269,11 @@ class MemSlab(MemManager):
|
||||
# MemBuddy - Buddy system allocator
|
||||
# Free list head array stored at arena start; subsequent memory managed in power-of-two sized blocks
|
||||
# Thread-safe (spinlock enabled), supports block coalescing
|
||||
#
|
||||
# Checkpoint 支持(供编译器等长任务回收阶段性分配):
|
||||
# mark() → 返回当前分配水位(不分配内存)
|
||||
# reset_to(m) → 释放水位 m 之后分配的所有块(回收到 free list)
|
||||
# 记录栈从 usable 顶部预留 _CHK_RESERVE 字节,不参与 buddy 分配。
|
||||
# ============================================================
|
||||
class MemBuddy(MemManager):
|
||||
# Override parent __provides__: MemBuddy provides both __mbuddy__ and __memmgr__.
|
||||
@@ -265,6 +285,10 @@ class MemBuddy(MemManager):
|
||||
lock_val: t.CVolatile | t.CInt # Spinlock
|
||||
usable: t.CVoid | t.CPtr # Start of usable memory region (skips free_lists)
|
||||
usable_size: t.CSizeT # Size of usable memory (power of two)
|
||||
chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址)
|
||||
chk_cap: t.CSizeT # 记录栈容量(条目数)
|
||||
chk_depth: t.CSizeT # 当前记录深度
|
||||
chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区)
|
||||
|
||||
def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT):
|
||||
self.base = base
|
||||
@@ -274,6 +298,10 @@ class MemBuddy(MemManager):
|
||||
self.lock_val = 0
|
||||
self.usable = None
|
||||
self.usable_size = 0
|
||||
self.chk_stack = None
|
||||
self.chk_cap = 0
|
||||
self.chk_depth = 0
|
||||
self.chk_base = None
|
||||
|
||||
self.lock_val = 0
|
||||
fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8
|
||||
@@ -291,6 +319,12 @@ class MemBuddy(MemManager):
|
||||
return
|
||||
|
||||
remaining: t.CSizeT = size - fl_bytes
|
||||
|
||||
# 注意:不能在 __init__ 里预留 checkpoint 记录栈!
|
||||
# buddy 区必须从 fl_bytes 后开始、大小必须是 2 的幂。
|
||||
# 若预留 512KB,remaining = 2^30 - 512KB 不是 2 的幂,
|
||||
# _largest_pow2_le 会取到 2^29 = 512MB,1GB 池直接砍半。
|
||||
# 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。
|
||||
usable: t.CSizeT = _largest_pow2_le(remaining)
|
||||
|
||||
if usable < MEMBUDDY_MIN_BLOCK:
|
||||
@@ -312,6 +346,60 @@ class MemBuddy(MemManager):
|
||||
# Entire usable memory region as a max_order free block
|
||||
self._fl_push(self.max_order, self.usable)
|
||||
|
||||
# === Checkpoint support ===
|
||||
|
||||
def mark(self) -> t.CSizeT:
|
||||
"""返回当前分配水位(checkpoint)
|
||||
|
||||
记录栈用 stdlib.malloc 分配(64K 条目 × 8B = 512KB,独立于 buddy 区),
|
||||
首次调用时懒分配。这样不占用 buddy 池、不会把 1GB 池砍半、
|
||||
reset_to 也不会误释放栈自身。
|
||||
"""
|
||||
if self.chk_stack is None:
|
||||
# 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、
|
||||
# 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。
|
||||
cap: t.CSizeT = 64 * 1024
|
||||
base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr)
|
||||
if base is None:
|
||||
return 0
|
||||
self.chk_base = base
|
||||
self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(base, t.CPtr))
|
||||
self.chk_cap = cap
|
||||
self.chk_depth = 0
|
||||
return self.chk_depth
|
||||
|
||||
def reset_to(self, mark: t.CSizeT):
|
||||
"""释放水位 mark 之后分配的所有块,回收到 free list
|
||||
|
||||
栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还;
|
||||
若已被单独 free(header==0),跳过避免重复归还。
|
||||
"""
|
||||
if self.chk_stack is None:
|
||||
return
|
||||
if mark >= self.chk_depth:
|
||||
return
|
||||
self._lock()
|
||||
while self.chk_depth > mark:
|
||||
self.chk_depth -= 1
|
||||
block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[self.chk_depth], t.CPtr)
|
||||
if block is None:
|
||||
continue
|
||||
stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr)
|
||||
stored_val: t.CUInt64T = t.CUInt64T(stored)
|
||||
if (stored_val & 1) == 0:
|
||||
continue # 已被单独 free,跳过
|
||||
order: t.CInt = t.CInt(stored_val >> 1)
|
||||
if order < 0 or order > self.max_order:
|
||||
continue
|
||||
self._coalesce(block, order)
|
||||
self._unlock()
|
||||
|
||||
def reset_all(self):
|
||||
"""回收全部已分配块(等价 reset_to(0))"""
|
||||
if self.chk_stack is None:
|
||||
return
|
||||
self.reset_to(0)
|
||||
|
||||
# === Free list operations ===
|
||||
|
||||
def _fl_push(self, order: t.CInt, block: t.CVoid | t.CPtr):
|
||||
@@ -405,6 +493,24 @@ class MemBuddy(MemManager):
|
||||
order: t.CInt = t.CInt(stored_val >> 1)
|
||||
if order < 0: return 0
|
||||
if order > self.max_order: return 0
|
||||
# 记录栈一致性校验:分配时(alloc)每个 block 地址都会压入 chk_stack。
|
||||
# reset_to(mark) 会把 [mark, chk_depth) 的块弹栈并归还 free list,
|
||||
# 之后这些地址会被重新分配。若一个 header 恰好是合法奇数(假阳性),
|
||||
# 但地址不在当前 chk_stack[0..chk_depth) 存活区间内,说明已被回收,
|
||||
# 不能当作有效指针(否则 _format_func_type_str/TypePrint 会沿垃圾链
|
||||
# 无限分配导致 OOM)。
|
||||
# 注意:chk_stack 容量满(64K)后 alloc 不再记录新块(chk_depth==chk_cap),
|
||||
# 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。
|
||||
if self.chk_stack is not None and self.chk_depth < self.chk_cap:
|
||||
alive: t.CInt = 0
|
||||
ci: t.CSizeT = 0
|
||||
while ci < self.chk_depth:
|
||||
if self.chk_stack[ci] == t.CUInt64T(block):
|
||||
alive = 1
|
||||
break
|
||||
ci += 1
|
||||
if alive == 0:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
# === Spinlock ===
|
||||
@@ -430,6 +536,10 @@ class MemBuddy(MemManager):
|
||||
if block is not None:
|
||||
c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr))
|
||||
result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr)
|
||||
# 记录到 checkpoint 栈(供 reset_to 回收)
|
||||
if self.chk_stack is not None and self.chk_depth < self.chk_cap:
|
||||
self.chk_stack[self.chk_depth] = t.CUInt64T(block)
|
||||
self.chk_depth += 1
|
||||
if result is None:
|
||||
# Allocation failure: print memory usage statistics and exit with OOM
|
||||
fb: t.CSizeT = self.free_bytes()
|
||||
@@ -439,7 +549,7 @@ class MemBuddy(MemManager):
|
||||
stdio.printf("[OOM] 内存池: total=%zu used=%zu free=%zu free_blocks=%zu\n",
|
||||
self.usable_size, ub, fb, self.free_count())
|
||||
stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n")
|
||||
sys.exit(1)
|
||||
stdlib.exit(1)
|
||||
self._unlock()
|
||||
return result
|
||||
|
||||
|
||||
+21
-20
@@ -7,106 +7,107 @@ import os._win32
|
||||
import os._posix
|
||||
|
||||
|
||||
# os 包入口
|
||||
# 根据 platmacro.IS_WINDOWS 分派到 _win32 或 _posix 后端
|
||||
# os.path 为跨平台纯字符串操作,直接可用
|
||||
# os package entry point
|
||||
# Dispatches to _win32 or _posix backend based on platmacro.IS_WINDOWS
|
||||
# os.path is for cross-platform pure string operations, can be used directly
|
||||
|
||||
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
|
||||
# Module-level global MBuddy pointer (initialized by the user in main)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录属性查询
|
||||
# File/Directory Attribute Query
|
||||
# =============================================================================
|
||||
|
||||
def exists(path: str) -> bool:
|
||||
"""检查文件/目录是否存在"""
|
||||
"""Check if the file/directory exists"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.exists(path)
|
||||
return os._posix.exists(path)
|
||||
|
||||
|
||||
def isdir(path: str) -> bool:
|
||||
"""检查路径是否为目录"""
|
||||
"""Check if the path is a directory"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isdir(path)
|
||||
return os._posix.isdir(path)
|
||||
|
||||
|
||||
def isfile(path: str) -> bool:
|
||||
"""检查路径是否为普通文件"""
|
||||
"""Check if the path is a regular file"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.isfile(path)
|
||||
return os._posix.isfile(path)
|
||||
|
||||
|
||||
def getsize(path: str) -> t.CInt64T:
|
||||
"""返回文件大小(字节)。失败返回 -1。"""
|
||||
"""Returns the file size (in bytes). Returns -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getsize(path)
|
||||
return os._posix.getsize(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 工作目录
|
||||
# Working Directory
|
||||
# =============================================================================
|
||||
|
||||
def getcwd() -> str:
|
||||
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
|
||||
"""Return the current working directory (memory allocated via _mbuddy)"""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.getcwd()
|
||||
return os._posix.getcwd_impl()
|
||||
|
||||
|
||||
def chdir(path: str) -> int:
|
||||
"""切换当前工作目录。成功返回 0,失败返回 -1。"""
|
||||
"""Switch the current working directory. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chdir(path)
|
||||
return os._posix.chdir_impl(path)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 文件/目录操作
|
||||
# File/Directory Operations
|
||||
# =============================================================================
|
||||
|
||||
def mkdir(path: str) -> int:
|
||||
"""创建目录。成功返回 0,失败返回 -1。"""
|
||||
"""Create a directory. Returns 0 on success, -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.mkdir(path)
|
||||
return os._posix.mkdir_impl(path)
|
||||
|
||||
|
||||
def remove(path: str) -> int:
|
||||
"""删除文件。成功返回 0,失败返回 -1。"""
|
||||
"""Delete the file. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.remove(path)
|
||||
return os._posix.remove(path)
|
||||
|
||||
|
||||
def rmdir(path: str) -> int:
|
||||
"""删除空目录。成功返回 0,失败返回 -1。"""
|
||||
"""Delete empty directories. Returns 0 if successful, -1 if it fails."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.rmdir(path)
|
||||
return os._posix.rmdir_impl(path)
|
||||
|
||||
|
||||
def rename(old_path: str, new_path: str) -> int:
|
||||
"""重命名/移动文件或目录。成功返回 0,失败返回 -1。"""
|
||||
"""Rename/move a file or directory. Returns 0 on success, -1 on failure."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.rename(old_path, new_path)
|
||||
return os._posix.rename_impl(old_path, new_path)
|
||||
|
||||
|
||||
def chmod(path: str, mode: int) -> int:
|
||||
"""修改文件权限。成功返回 0,失败返回 -1。
|
||||
Windows 上只处理只读位(S_IWUSR);POSIX 上使用完整权限位。"""
|
||||
"""Modify file permissions. Returns 0 on success, -1 on failure.
|
||||
On Windows, only the read-only bit (S_IWUSR) is handled;
|
||||
On POSIX, full permission bits are used."""
|
||||
if platmacro.IS_WINDOWS:
|
||||
return os._win32.chmod(path, mode)
|
||||
return os._posix.chmod_impl(path, mode)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 目录列举
|
||||
# Table of Contents Listing
|
||||
# =============================================================================
|
||||
|
||||
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ def _rmtree_posix(path: str) -> int:
|
||||
|
||||
path_len: t.CSizeT = len(path)
|
||||
result: int = 0
|
||||
entry: posix.Dirent = posix.readdir(dirp)
|
||||
entry: posix.Dirent | t.CPtr = posix.readdir(dirp)
|
||||
while entry != None:
|
||||
name: str = entry.d_name
|
||||
# Skip . and ..
|
||||
|
||||
+2
-1
@@ -6,4 +6,5 @@ def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass
|
||||
def free(p: t.CVoid | t.CPtr) -> t.State: pass
|
||||
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass
|
||||
def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass
|
||||
def exit(status: int) -> t.State: pass
|
||||
@@ -385,5 +385,5 @@ class FileW:
|
||||
def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr:
|
||||
return File(filename, mode, share)
|
||||
|
||||
def openw(filename: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
def openw(filename: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr:
|
||||
return FileW(filename, mode, share)
|
||||
@@ -1,3 +1,5 @@
|
||||
# from string import memset, memcpy
|
||||
# from stdio import malloc, free, calloc, realloc
|
||||
from stdint import *
|
||||
import zlib.zdeflate as zdeflate
|
||||
import zlib.zinflate as zinflate
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from stdint import *
|
||||
import stddef
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
|
||||
@@ -3,10 +3,9 @@ import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes
|
||||
|
||||
from lib.core.VLogger import Logger, LogLevel, set_logger
|
||||
|
||||
# 创建全局日志实例
|
||||
# 创建全局日志实例(仅控制台输出,不落盘,避免生成 build.log)
|
||||
logger = Logger(
|
||||
name="TransPyC",
|
||||
log_file="build.log",
|
||||
level=LogLevel.INFO,
|
||||
use_colors=True
|
||||
)
|
||||
|
||||
@@ -1442,6 +1442,11 @@ class AssignHandle(BaseHandle):
|
||||
VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(VarType, ir.VoidType):
|
||||
VarType = ir.IntType(32)
|
||||
# 记录模块级注解类型:供函数内 global 变量的 += (HandlesAugAssign)参考,
|
||||
# 避免用 RHS 字面量类型(i32)误建 i32 全局导致 i64/i32 类型不匹配。
|
||||
if not hasattr(Gen, '_module_ann_types'):
|
||||
Gen._module_ann_types = {}
|
||||
Gen._module_ann_types[VarName] = VarType
|
||||
if VarName in Gen.variables or VarName in Gen.module.globals:
|
||||
# 时序修复:第一遍创建全局时类未处理(SymbolTable 无枚举成员),
|
||||
# initializer 回退为 0。第二遍类已处理,尝试用解析出的枚举值更新 initializer。
|
||||
|
||||
@@ -19,8 +19,27 @@ class AugAssignHandle(BaseHandle):
|
||||
ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__',
|
||||
}
|
||||
|
||||
def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type:
|
||||
"""解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。
|
||||
|
||||
问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为
|
||||
`_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量
|
||||
类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配,
|
||||
产生 "Operands must be the same type, got (i64, i32)" 类错误。
|
||||
模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局,
|
||||
但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、
|
||||
Gen.module.globals 中无该符号,故需在此兜底解析注解类型。
|
||||
"""
|
||||
module_ann: dict = getattr(Gen, '_module_ann_types', None)
|
||||
if module_ann and VarName in module_ann:
|
||||
ann_type: ir.Type = module_ann[VarName]
|
||||
if ann_type is not None:
|
||||
return ann_type
|
||||
if isinstance(fallback, ir.IntType):
|
||||
return fallback
|
||||
return ir.IntType(64)
|
||||
|
||||
def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool:
|
||||
"""判断增量赋值操作是否应使用无符号指令"""
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Node.target, ast.Name):
|
||||
if Gen._check_node_unsigned(Node.target):
|
||||
@@ -92,7 +111,7 @@ class AugAssignHandle(BaseHandle):
|
||||
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
|
||||
GVar: ir.GlobalVariable
|
||||
if VarName not in Gen.module.globals:
|
||||
_gv_type: ir.Type = Value.type if isinstance(Value.type, ir.IntType) else ir.IntType(64)
|
||||
_gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type)
|
||||
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
|
||||
GVar.initializer = ir.Constant(_gv_type, 0)
|
||||
else:
|
||||
|
||||
@@ -631,8 +631,12 @@ class ClassHandle(BaseHandle):
|
||||
child_method: str = f"{ClassName}.{method_name}"
|
||||
new_methods.append(child_method)
|
||||
Gen.register_method(ClassName, child_method)
|
||||
covered_names.add(method_name)
|
||||
# 添加子类新增方法(不在父类中的)
|
||||
for m in Gen.class_methods[ClassName]:
|
||||
# 用快照遍历:register_method 会原地修改 class_methods,
|
||||
# 若遍历活列表会把父类独有方法(已由 register_method 追加)再次追加,
|
||||
# 导致 vtable 槽数与跨模块调用方推断不一致(如 MemBuddy 36 槽 vs 28 槽)。
|
||||
for m in list(Gen.class_methods[ClassName]):
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
if method_name not in covered_names:
|
||||
new_methods.append(m)
|
||||
|
||||
@@ -7,16 +7,8 @@ from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
# [CDF-LOAD] 模块加载标记:用于确认修复后的代码被实际加载
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write('[CDF-LOAD] HandlesExprAttr.py loaded (with CDefine fix)\n')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class ExprAttrHandle(BaseHandle):
|
||||
|
||||
# ========== 辅助方法 ==========
|
||||
|
||||
def _apply_bswap_on_Load(self, val: ir.Value, ClassName: str, AttrName: str) -> ir.Value:
|
||||
@@ -205,20 +197,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
for key in (f"{VarName}.{AttrName}", AttrName):
|
||||
if key in define_constants:
|
||||
return self._make_define_constant(Gen, define_constants[key])
|
||||
# [CDF-DBG] CDefine 查找失败时的诊断输出
|
||||
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
_dbg_keys: list[str] = []
|
||||
for _k in PossibleKeys:
|
||||
_si: Any = self.Trans.SymbolTable.lookup(_k)
|
||||
_dbg_keys.append(f"{_k}=>si={_si is not None},isdef={getattr(_si, 'IsDefine', None)},dv={getattr(_si, 'DefineValue', None)}")
|
||||
_dc_keys: list[str] = [f"{k}=>{define_constants.get(k, '<miss>')}" for k in (f"{VarName}.{AttrName}", AttrName)]
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[CDF-DBG] miss VarName={VarName} AttrName={AttrName} imported_modules={imported_modules}\n")
|
||||
_f.write(f"[CDF-DBG] sym_keys={_dbg_keys}\n")
|
||||
_f.write(f"[CDF-DBG] dc_keys={_dc_keys}\n")
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
def _lookup_module_global(self, Gen: LlvmCodeGenerator, VarName: str, AttrName: str) -> ir.Value | None:
|
||||
@@ -420,18 +398,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
AttrName: str = Node.attr
|
||||
|
||||
# [HAN-DBG] 入口诊断:标记 CONST_* 属性访问
|
||||
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
_in_globals: bool = AttrName in Gen.module.globals
|
||||
_gv_type: Any = None
|
||||
if _in_globals:
|
||||
_gv_type = str(Gen.module.globals[AttrName].type)
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[HAN-DBG] enter VarName={VarName} AttrName={AttrName} in_globals={_in_globals} gv_type={_gv_type}\n")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# __doc__ 魔法字符串:函数/结构体的 docstring
|
||||
if AttrName == '__doc__':
|
||||
doc_ptr: ir.Value | None = Gen._get_doc_ptr(VarName)
|
||||
@@ -462,12 +428,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
# 尝试 import 模块全局变量
|
||||
result = self._lookup_module_global(Gen, VarName, AttrName)
|
||||
if result is not None:
|
||||
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[HAN-DBG] module_global HIT VarName={VarName} AttrName={AttrName} result_type={result.type}\n")
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
|
||||
# FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储)
|
||||
@@ -488,12 +448,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
# 尝试 attr 直接作为全局变量(仅当 VarName 不是结构体变量时)
|
||||
if not ClassName and AttrName in Gen.module.globals:
|
||||
gv: Any = Gen.module.globals[AttrName]
|
||||
if AttrName in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[HAN-DBG] FALLBACK_TO_GLOBAL VarName={VarName} AttrName={AttrName} gv_type={gv.type}\n")
|
||||
except Exception:
|
||||
pass
|
||||
if AttrName in Gen.variables and Gen.variables[AttrName] is None:
|
||||
str_gv_name: str = AttrName + '_str'
|
||||
if str_gv_name in Gen.module.globals:
|
||||
@@ -899,20 +853,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
def _HandleAttributeLlvm(self, Node: ast.Attribute) -> ir.Value | None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
# [ATTR-DBG] 入口诊断:标记 CONST_* 属性访问的派发路径
|
||||
if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
_val_kind: str = type(Node.value).__name__
|
||||
_val_id: str = ''
|
||||
if isinstance(Node.value, ast.Name):
|
||||
_val_id = Node.value.id
|
||||
elif isinstance(Node.value, ast.Attribute):
|
||||
_val_id = f"<Attribute attr={Node.value.attr}>"
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[ATTR-DBG] dispatch Node.attr={Node.attr} value_kind={_val_kind} value_id={_val_id}\n")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if isinstance(Node.value, ast.Name):
|
||||
VarName: str = Node.value.id
|
||||
# 处理 t/c import 的别名重定向
|
||||
@@ -921,12 +861,6 @@ class ExprAttrHandle(BaseHandle):
|
||||
src_module: str
|
||||
src_name: str
|
||||
src_module, src_name = t_c_imported[VarName]
|
||||
if Node.attr in ('CONST_INT', 'CONST_FLOAT', 'CONST_STR', 'CONST_BOOL', 'CONST_NONE'):
|
||||
try:
|
||||
with open('d:/Users/TermiNexus/Desktop/TransPyC/_attr_debug.log', 'a', encoding='utf-8') as _f:
|
||||
_f.write(f"[ATTR-DBG] REDIRECT VarName={VarName} -> src_module={src_module} src_name={src_name}\n")
|
||||
except Exception:
|
||||
pass
|
||||
virtual_attr: ast.Attribute = ast.Attribute(
|
||||
value=ast.Name(id=src_module, ctx=ast.Load()),
|
||||
attr=src_name, ctx=ast.Load()
|
||||
|
||||
@@ -1726,14 +1726,16 @@ class FunctionHandle(BaseHandle):
|
||||
triple = getattr(Gen, 'module_triple', '') or getattr(Gen.module, 'triple', '')
|
||||
is_windows = 'windows' in triple if triple else False
|
||||
ptr_size = getattr(Gen, 'ptr_size', 8)
|
||||
# va_list 大小取决于 ABI:Windows x64 = 1个指针,Linux x64 = __va_list_tag[1](24字节)
|
||||
# 32位平台:Windows = 4字节指针,Linux = 12字节
|
||||
# va_list 大小取决于 ABI:Windows x64 = __va_list_tag(24字节),Linux x64 = __va_list_tag[1](24字节)
|
||||
# 注意:x86_64-pc-windows-gnu 的 llvm.va_start 写的是 24 字节的 struct __va_list_tag
|
||||
# ({i32 gp_offset, i32 fp_offset, i8* overflow_arg_area, i8* reg_save_area}),
|
||||
# 若只分配 8 字节会向调用者栈帧越界写 16 字节,导致随机栈破坏(历史崩溃根因)。
|
||||
if ptr_size == 4:
|
||||
va_list_size = 4 if is_windows else 12
|
||||
va_list_align = 4
|
||||
else:
|
||||
va_list_size = 8 if is_windows else 24
|
||||
va_list_align = 8 if is_windows else 16
|
||||
va_list_size = 24
|
||||
va_list_align = 16
|
||||
va_list_type = ir.ArrayType(ir.IntType(8), va_list_size)
|
||||
va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align)
|
||||
va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr")
|
||||
|
||||
@@ -155,6 +155,24 @@ class ExprGenMixin:
|
||||
'|': self.builder.or_,
|
||||
'^': self.builder.xor,
|
||||
}
|
||||
# 整数操作数宽度对齐:两个操作数都是整数但位宽不同时,
|
||||
# 统一扩展到较大位宽(低位宽操作数 zext/sext)。
|
||||
# 触发场景:`_g_alloc_count: t.CSizeT = 0`(i64 全局)在函数内
|
||||
# `_g_alloc_count += 1`,RHS 整数字面量是 i32,不扩展会报
|
||||
# "Operands must be the same type, got (i64, i32)"。
|
||||
if (op in ops or op in shift_ops or op in bit_ops or op in cmp_ops):
|
||||
if (isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType)
|
||||
and left.type != right.type and left.type.width != 1 and right.type.width != 1):
|
||||
if left.type.width > right.type.width:
|
||||
if is_unsigned:
|
||||
right = self.builder.zext(right, left.type, name="zext_rhs_op")
|
||||
else:
|
||||
right = self.builder.sext(right, left.type, name="sext_rhs_op")
|
||||
elif right.type.width > left.type.width:
|
||||
if is_unsigned:
|
||||
left = self.builder.zext(left, right.type, name="zext_lhs_op")
|
||||
else:
|
||||
left = self.builder.sext(left, right.type, name="sext_lhs_op")
|
||||
if op == '**' or op == 'Pow':
|
||||
if isinstance(left, ir.Constant) and isinstance(right, ir.Constant):
|
||||
try:
|
||||
|
||||
Whitespace-only changes.
-478
@@ -1,478 +0,0 @@
|
||||
===== TransPyV Test Suite =====
|
||||
|
||||
asm: nop ok
|
||||
asm: nop2 ok
|
||||
asm: multi-clobber ok
|
||||
asm: input ok val=42
|
||||
asm: output result=123
|
||||
asm: in+out result2=11 (expect 11)
|
||||
=== attr_test: c.Attribute 装饰器测试 ===
|
||||
|
||||
--- Test 1: c.Attribute(always_inline) ---
|
||||
AlwaysInlineFunc(21)=42 (expect 42)
|
||||
AlwaysInlineFunc OK
|
||||
--- Test 2: c.Attribute(noinline) ---
|
||||
NoInlineFunc(5)=105 (expect 105)
|
||||
NoInlineFunc OK
|
||||
--- Test 3: c.Attribute(noreturn) ---
|
||||
NoReturnFunc declared with noreturn attr
|
||||
NoReturnFunc OK (not called to avoid UB)
|
||||
--- Test 4: normal function (no attr) ---
|
||||
NormalFunc(7)=21 (expect 21)
|
||||
NormalFunc OK
|
||||
--- Test 5: c.Attribute(always_inline, pure) ---
|
||||
MultiAttrFunc(10)=11 (expect 11)
|
||||
MultiAttrFunc OK
|
||||
--- Test 6: c.Attribute(packed) ---
|
||||
PackedAttrFunc(10)=9 (expect 9)
|
||||
PackedAttrFunc OK
|
||||
--- Test 7: c.Attribute(llvm.nounwind) ---
|
||||
NoUnwindFunc(10)=11 (expect 11)
|
||||
NoUnwindFunc OK
|
||||
--- Test 8: c.Attribute(llvm.noredzone) ---
|
||||
NoRedZoneFunc(10)=12 (expect 12)
|
||||
NoRedZoneFunc OK
|
||||
--- Test 9: c.Attribute(llvm.willreturn) ---
|
||||
WillReturnFunc(10)=13 (expect 13)
|
||||
WillReturnFunc OK
|
||||
--- Test 10: c.Attribute(llvm.mustprogress) ---
|
||||
MustProgressFunc(10)=14 (expect 14)
|
||||
MustProgressFunc OK
|
||||
--- Test 11: c.Attribute(const) ---
|
||||
ConstFunc(99)=42 (expect 42)
|
||||
ConstFunc OK
|
||||
--- Test 12: c.Attribute(always_inline, nounwind, noredzone) ---
|
||||
TripleAttrFunc(10)=15 (expect 15)
|
||||
TripleAttrFunc OK
|
||||
|
||||
=== attr_test 完成 ===
|
||||
local +=: 15
|
||||
local -=: 12
|
||||
local *=: 24
|
||||
local /=: 6
|
||||
local %=: 6
|
||||
global +=: 1
|
||||
global +=: 11
|
||||
global -=: 8
|
||||
bit &=: 15
|
||||
bit |=: 63
|
||||
bit ^=: 192
|
||||
bit <<=: 16
|
||||
bit >>=: 4
|
||||
global: 9
|
||||
global: 10
|
||||
global: 11
|
||||
closure: 1
|
||||
closure: 1
|
||||
closure: 1
|
||||
=== deco_test: t/c 装饰器测试 ===
|
||||
|
||||
--- Test 1: t.CDefine ---
|
||||
MAX_VALUE=256 (expect 256)
|
||||
PI_APPROX=314 (expect 314)
|
||||
MAX_VALUE OK
|
||||
PI_APPROX OK
|
||||
--- Test 2: t.CExport ---
|
||||
ExportedAdd(3,4)=7 (expect 7)
|
||||
ExportedAdd OK
|
||||
--- Test 3: t.CInline ---
|
||||
InlineSquare(5)=25 (expect 25)
|
||||
InlineSquare OK
|
||||
--- Test 4: normal function ---
|
||||
NormalSub(10,3)=7 (expect 7)
|
||||
NormalSub OK
|
||||
--- Test 5: t.CExport | t.CInline ---
|
||||
ExportedInlineCube(3)=27 (expect 27)
|
||||
ExportedInlineCube OK
|
||||
--- Test 6: t.CExport return ptr ---
|
||||
ExportedFindChar found, char=108 (expect 108)
|
||||
ExportedFindChar OK
|
||||
--- Test 7: t.CExtern | t.CExport ---
|
||||
ExternalDecl declared (not called)
|
||||
ExternalDecl OK
|
||||
--- Test 8: t.State ---
|
||||
StateDecl declared (not called)
|
||||
StateDecl OK
|
||||
--- Test 9: t.State (void) ---
|
||||
StateVoidDecl declared (not called)
|
||||
StateVoidDecl OK
|
||||
--- Test 10: t.CArray[elem, CDefine] ---
|
||||
ARR_SIZE=8 (expect 8)
|
||||
arr sum=280 (expect 280)
|
||||
arr[0]=0 (expect 0)
|
||||
arr[7]=70 (expect 70)
|
||||
CArray CDefine count OK
|
||||
|
||||
=== deco_test 完成 ===
|
||||
deref: 104
|
||||
ptr: len(hello)=5
|
||||
=== eq_test: ==、!=、is、None 比较测试 ===
|
||||
|
||||
--- Test 1: int == / != ---
|
||||
int == int (same) OK
|
||||
int != int (diff) OK
|
||||
not (int == diff) OK
|
||||
--- Test 2: int < > <= >= ---
|
||||
int < OK
|
||||
int > OK
|
||||
int <= OK
|
||||
int >= OK
|
||||
--- Test 3: ptr is None / is not None ---
|
||||
strchr found, is not None OK
|
||||
strchr not found, is None OK
|
||||
--- Test 4: assign None and compare ---
|
||||
None assign, is None OK
|
||||
None assign, is not None OK
|
||||
--- Test 5: ptr == None / != None ---
|
||||
strstr found, != None OK
|
||||
strstr not found, == None OK
|
||||
--- Test 6: bool and/or ---
|
||||
1 and 0 = false OK
|
||||
1 or 0 = true OK
|
||||
not 0 = true OK
|
||||
|
||||
=== eq_test 完成 ===
|
||||
float: f=3.140000
|
||||
double: d=3.141593
|
||||
float: f=2.500000
|
||||
union: u.f=3.140000
|
||||
union: u.i=42 (after f overwritten)
|
||||
union: float overwrites int verified
|
||||
arith: 1.50 + 2.50 = 4.00
|
||||
arith: 1.50 - 2.50 = -1.00
|
||||
arith: 1.50 * 2.50 = 3.75
|
||||
arith: 1.50 / 2.50 = 0.60
|
||||
arith: 10.0000 + 3.0000 = 13.0000
|
||||
arith: 10.0000 - 3.0000 = 7.0000
|
||||
arith: 10.0000 * 3.0000 = 30.0000
|
||||
arith: 10.0000 / 3.0000 = 3.3333
|
||||
arith: 10.0 % 3.0 = 1.0000
|
||||
arith: 3 + 1.50 = 4.50
|
||||
while: total=10 i=5
|
||||
break: k=0
|
||||
break: k=1
|
||||
break: k=2
|
||||
continue: m=0
|
||||
continue: m=1
|
||||
continue: m=3
|
||||
continue: m=4
|
||||
for: j=0
|
||||
for: j=1
|
||||
for: j=2
|
||||
for: j=3
|
||||
for: j=4
|
||||
add(3,4)=7
|
||||
mul(5,6)=30
|
||||
square(7)=49
|
||||
factorial(5)=120
|
||||
add(b=4,a=3)=7
|
||||
sub(b=3,a=10)=7
|
||||
Hello, World!
|
||||
Hello, World!
|
||||
greet mixed: returned=2
|
||||
Hi, TransPyC!
|
||||
greet kwargs: returned=1
|
||||
=== llvmir_test: c.LLVMIR 内联 LLVM IR 测试 ===
|
||||
|
||||
--- Test 1: LLVMIR add ---
|
||||
add(10, 20)=30 (expect 30)
|
||||
LLVMIR add OK
|
||||
--- Test 2: LLVMIR sub ---
|
||||
sub(50, 20)=30 (expect 30)
|
||||
LLVMIR sub OK
|
||||
--- Test 3: LLVMIR mul ---
|
||||
mul(6, 7)=42 (expect 42)
|
||||
LLVMIR mul OK
|
||||
--- Test 4: LLVMIR sdiv ---
|
||||
sdiv(100, 4)=25 (expect 25)
|
||||
LLVMIR sdiv OK
|
||||
--- Test 5: LLVMIR and ---
|
||||
and(255, 15)=15 (expect 15)
|
||||
LLVMIR and OK
|
||||
--- Test 6: LLVMIR or ---
|
||||
or(240, 15)=255 (expect 255)
|
||||
LLVMIR or OK
|
||||
--- Test 7: LLVMIR xor ---
|
||||
xor(255, 15)=240 (expect 240)
|
||||
LLVMIR xor OK
|
||||
--- Test 8: LLVMIR shl ---
|
||||
shl(1, 4)=16 (expect 16)
|
||||
LLVMIR shl OK
|
||||
--- Test 9: LLVMIR LOut ---
|
||||
LOut add(10, 20)=30 (expect 30)
|
||||
LLVMIR LOut OK
|
||||
--- Test 10: LLVMIR icmp eq ---
|
||||
icmp eq(5, 5)=-1 (expect nonzero)
|
||||
LLVMIR icmp eq OK
|
||||
--- Test 11: LLVMIR icmp ne ---
|
||||
icmp ne(5, 3)=-1 (expect nonzero)
|
||||
LLVMIR icmp ne OK
|
||||
--- Test 12: LLVMIR icmp slt ---
|
||||
icmp slt(3, 5)=-1 (expect nonzero)
|
||||
LLVMIR icmp slt OK
|
||||
--- Test 13: LLVMIR srem ---
|
||||
srem(17, 5)=2 (expect 2)
|
||||
LLVMIR srem OK
|
||||
--- Test 14: LLVMIR lshr ---
|
||||
lshr(256, 2)=64 (expect 64)
|
||||
LLVMIR lshr OK
|
||||
--- Test 15: LLVMIR nested in expression ---
|
||||
(LLVMIR add(10,20)) + 10 = 40 (expect 40)
|
||||
LLVMIR nested OK
|
||||
|
||||
=== llvmir_test 完成 ===
|
||||
oop: === Test 1: Basic Methods ===
|
||||
oop: p.x=10 p.y=20
|
||||
oop: after move p.x=100 p.y=200
|
||||
oop: === Test 2: Defaults + Methods ===
|
||||
oop: initial count=0 step=1
|
||||
oop: after 3 increments: 1 2 3
|
||||
oop: after reset+increment: 1
|
||||
oop: === Test 3: __init__ ===
|
||||
oop: rect 3x4 area=12
|
||||
oop: === All OOP Tests Passed ===
|
||||
ptr: len(hello)=5
|
||||
ptr: after DerefAs x=88
|
||||
ptr: sum(A,B,C)=198
|
||||
if: x is truthy
|
||||
if: 1==1 is truthy
|
||||
while: total=10 i=5
|
||||
for: j=0
|
||||
for: j=1
|
||||
for: j=2
|
||||
for: j=3
|
||||
for: j=4
|
||||
break: k=0
|
||||
break: k=1
|
||||
break: k=2
|
||||
continue: m=0
|
||||
continue: m=1
|
||||
continue: m=3
|
||||
continue: m=4
|
||||
bool: x>5 and x<100 is true
|
||||
bool: x>100 or x>5 is true
|
||||
ptr: len(hello)=5
|
||||
ptr: after DerefAs v=88
|
||||
ptr: sum(A,B,C)=198
|
||||
ptr: c.Load v2=42 (expected 42)
|
||||
ptr: c.Load overwrite v3=200 (expected 200)
|
||||
ptr: c.Load src unchanged v5=999 v6=999 (expected 999, 999)
|
||||
hello
|
||||
strlen(Hello)=5
|
||||
=== string_test: string.py 库函数测试 ===
|
||||
|
||||
--- Test 1: strlen ---
|
||||
strlen(Hello)=5 (expect 5)
|
||||
strlen()=0 (expect 0)
|
||||
strlen(Hello, World!)=13 (expect 13)
|
||||
--- Test 2: strcmp ---
|
||||
strcmp(abc,abc)=0 (expect 0)
|
||||
strcmp(abc,abd)=-1 (expect <0)
|
||||
strcmp(abd,abc)=1 (expect >0)
|
||||
--- Test 3: strncmp ---
|
||||
strncmp(abcdef,abcXYZ,3)=0 (expect 0)
|
||||
strncmp(abcdef,abcXYZ,4)=12 (expect <0)
|
||||
--- Test 4: atoi ---
|
||||
atoi(123)=123 (expect 123)
|
||||
atoi(-456)=-456 (expect -456)
|
||||
atoi( 789)=789 (expect 789)
|
||||
--- Test 5: strchr ---
|
||||
strchr(Hello,'l') found, char=108 (expect 108)
|
||||
strchr(Hello,'z') not found OK
|
||||
--- Test 6: strstr ---
|
||||
strstr(Hello,World) found OK
|
||||
strstr(Hello,xyz) not found OK
|
||||
|
||||
=== string_test 完成 ===
|
||||
struct: p.x=10 p.y=20
|
||||
struct: modified p.x=100 p.y=200
|
||||
struct: sum=300
|
||||
struct: volume=60
|
||||
array: total=1500
|
||||
array: arr[2]=999
|
||||
ptr: len(hello)=5
|
||||
ptr: sum(A,B,C)=198
|
||||
ctor: z.x=0 z.y=0
|
||||
ctor: p3.x=7 p3.y=8
|
||||
ctor: bx.w=10 bx.h=20 bx.d=30
|
||||
kw: p4.x=10 p4.y=20
|
||||
kw: p5.x=5 p5.y=15
|
||||
kw: bx2.w=10 bx2.h=20 bx2.d=30
|
||||
def: sz.w=100 sz.h=200
|
||||
def: sz2.w=5 sz2.h=6
|
||||
def: sz3.w=888 sz3.h=999
|
||||
def: sz4.w=7 sz4.h=200
|
||||
enum: Idle=0 Run=1 Stop=2
|
||||
enum: Red=10 Green=11 Blue=20 Yellow=21
|
||||
enum: Small=0 Big=1 Medium=2
|
||||
enum: sum(Idle,Run,Stop)=3
|
||||
enum: Idle==0 true
|
||||
enum: Red==10 true
|
||||
enum: Run!=Stop true
|
||||
union: u.i=42
|
||||
union: u.l=20015998343868
|
||||
union: shared memory verified
|
||||
type: CInt=100 CInt32T=200 CUInt32T=300
|
||||
type: CLong=1000 CLongLong=2000 CInt64T=3000 CSizeT=4000
|
||||
bit: 240&15=0
|
||||
bit: 240|15=255
|
||||
bit: 240^15=255
|
||||
bit: 240<<2=960
|
||||
bit: 240>>2=60
|
||||
bit: 17%5=2
|
||||
vtable: === Test Start ===
|
||||
vtable: a.GetName()=42 (expected 42)
|
||||
vtable: a.Speak()=0 (expected 0)
|
||||
vtable: s.SetSides(4)=0 (expected 0)
|
||||
vtable: s.GetSides()=4 (expected 4)
|
||||
vtable: === All Tests Passed ===
|
||||
inherit: === Test 1: Base Class ===
|
||||
inherit: a.GetName()=42 (expected 42)
|
||||
inherit: a.Speak()=0 (expected 0)
|
||||
inherit: === Test 2: Dog (override Speak) ===
|
||||
inherit: d.GetName()=100 (expected 100)
|
||||
inherit: d.Speak()=1 (expected 1)
|
||||
inherit: d.GetBreed()=7 (expected 7)
|
||||
inherit: === Test 3: Cat (inherit Speak) ===
|
||||
inherit: ct.GetName()=200 (expected 200)
|
||||
inherit: ct.Speak()=0 (expected 0)
|
||||
inherit: ct.GetColor()=3 (expected 3)
|
||||
inherit: === All Tests Passed ===
|
||||
funcvt: === Test Start ===
|
||||
funcvt: A.VirtualMethod()=15 (expected 15)
|
||||
funcvt: A.NormalMethod()=25 (expected 25)
|
||||
funcvt: B.KeptMethod()=37 (expected 37)
|
||||
funcvt: B.ExcludedMethod()=47 (expected 47)
|
||||
funcvt: C.VirtualMethod()=59 (expected 59)
|
||||
funcvt: C.NormalMethod()=69 (expected 69)
|
||||
funcvt: === All Tests Passed ===
|
||||
vdispatch: === Test Start ===
|
||||
vdispatch: === Test 1: Direct Dispatch ===
|
||||
vdispatch: a.Speak()=0 (expected 0)
|
||||
vdispatch: d.Speak()=1 (expected 1)
|
||||
vdispatch: === Test 2: Virtual Dispatch ===
|
||||
vdispatch: a.Speak()=1 (expected 1 after vtable copy)
|
||||
vdispatch: === Test 3: GetName After VTable Copy ===
|
||||
vdispatch: a.GetName()=42 (expected 42)
|
||||
vdispatch: === All Tests Passed ===
|
||||
new: === Test Start ===
|
||||
new: === Test 1: __new__ returns self ===
|
||||
new: WithNew.__new__ called
|
||||
new: WithNew.__init__ called
|
||||
new: w.GetValue()=42 (expected 42)
|
||||
new: === Test 2: __new__ no extra args ===
|
||||
new: WithNewNoArgs.__new__ called
|
||||
new: n.GetValue()=99 (expected 99)
|
||||
new: === Test 3: __new__ + vtable ===
|
||||
new: WithNewVTable.__new__ called
|
||||
new: vt.GetValue()=10 (expected 10)
|
||||
new: vt.Speak()=11 (expected 11)
|
||||
new: === All Tests Passed ===
|
||||
nsisol: === Test Start ===
|
||||
nsisol: === Test 1: from-import bare constructor ===
|
||||
nsisol: w.GetId()=42 (expected 42)
|
||||
nsisol: w.Render()=100 (expected 100)
|
||||
nsisol: g.Render()=200 (expected 200)
|
||||
nsisol: g.GetExtra()=9 (expected 9)
|
||||
nsisol: === Test 2: module-qualified constructor ===
|
||||
nsisol: ps.Sum()=30 (expected 30)
|
||||
nsisol: ps2.Sum()=11 (expected 11)
|
||||
nsisol: === Test 3: type annotation with imported class ===
|
||||
nsisol: annot_w.GetId()=99 (expected 99)
|
||||
nsisol: === Test 4: cross-module inheritance vtable ===
|
||||
nsisol: base.Render()=100 (expected 100)
|
||||
nsisol: derived.Render()=200 (expected 200)
|
||||
nsisol: derived.GetId()=2 (expected 2)
|
||||
nsisol: === All Tests Passed ===
|
||||
=== testcheck_test ===
|
||||
|
||||
--- Arithmetic ---
|
||||
PASS: 3+4=7
|
||||
PASS: 10-3=7
|
||||
PASS: 6*7=42
|
||||
--- String ---
|
||||
PASS: strlen(hello)=5
|
||||
PASS: strcmp(abc,abc)=0
|
||||
--- Module Import ---
|
||||
testcheck module imported and called successfully
|
||||
PASS: import testcheck works
|
||||
|
||||
--- Summary ---
|
||||
PASS: 6, FAIL: 0
|
||||
=== Operator Overload Tests ===
|
||||
|
||||
--- Counter __add__ ---
|
||||
PASS: cnt(10)+5=15
|
||||
--- Counter __sub__/__mul__/__div__/__mod__ ---
|
||||
PASS: cnt-3=7
|
||||
PASS: cnt*3=30
|
||||
PASS: cnt/3=3
|
||||
PASS: cnt%3=1
|
||||
--- Counter compare overloads ---
|
||||
PASS: cnt==10:1
|
||||
PASS: cnt!=10:0
|
||||
PASS: cnt<20:1
|
||||
PASS: cnt<=10:1
|
||||
PASS: cnt>5:1
|
||||
PASS: cnt>=10:1
|
||||
--- BitBox bitwise overloads ---
|
||||
PASS: bb&0x0F=15
|
||||
PASS: bb|0x100=511
|
||||
PASS: bb^0x55=170
|
||||
PASS: bb<<4=4080
|
||||
PASS: bb>>4=15
|
||||
--- Native int binop ---
|
||||
PASS: 7+8=15
|
||||
PASS: 10-3=7
|
||||
PASS: 4*5=20
|
||||
--- Native int compare ---
|
||||
PASS: 3<5
|
||||
PASS: 10==10
|
||||
--- Vec2 struct overloads ---
|
||||
PASS: a+b x=4
|
||||
PASS: a+b y=6
|
||||
PASS: a-b x=2
|
||||
PASS: a-b y=2
|
||||
--- Vec2 compare overloads ---
|
||||
PASS: (5,5)==(5,5):1
|
||||
PASS: (5,5)!=(5,5):0
|
||||
|
||||
--- Summary ---
|
||||
PASS: 27, FAIL: 0
|
||||
circ: === Test Start ===
|
||||
circ: === Test 1: A.MakeB() ===
|
||||
circ: a.GetValue()=10 (expected 10)
|
||||
circ: b.GetValue()=10 (expected 10)
|
||||
circ: === Test 2: B.MakeA() ===
|
||||
circ: a2.GetValue()=10 (expected 10)
|
||||
circ: === Test 3: value chain A(20)->B->A ===
|
||||
circ: final=20 (expected 20)
|
||||
circ: === All Tests Passed ===
|
||||
=== nested_match_test: 嵌套 match REnum 检测测试 ===
|
||||
|
||||
[DBG] _init_mbuddy: start
|
||||
[DBG] _init_mbuddy: malloc arena=0
|
||||
[DBG] _init_mbuddy: malloc mb=0
|
||||
[DBG] _init_mbuddy: before_init
|
||||
[DBG] _init_mbuddy: init
|
||||
[DBG] _init_mbuddy: store
|
||||
[DBG] _init_mbuddy: done
|
||||
--- Test 1: 单层 match LLVMType ---
|
||||
[DBG] Int32 done: 0
|
||||
Int(-693633024) OK
|
||||
bits==-693633024 FAIL
|
||||
--- Test 2: 嵌套 match(case 块内 match 另一值)---
|
||||
outer Int(-688782832), inner Int(0) OK
|
||||
values FAIL
|
||||
--- Test 3: 嵌套 match pointee ---
|
||||
--- Test 4: 3 层嵌套 match ---
|
||||
--- Test 5: if 块内嵌套 match ---
|
||||
Float(-688782320) + Double(0) OK
|
||||
float values FAIL
|
||||
--- Test 6: 嵌套 match 不同变体(default 分支)---
|
||||
outer Int(-688782192), inner Float(0) OK
|
||||
mismatch values FAIL
|
||||
|
||||
=== nested_match_test: SOME FAIL ===
|
||||
|
||||
===== Test Suite Complete =====
|
||||
@@ -1 +0,0 @@
|
||||
===== Test Suite Complete =====
|
||||
Reference in new issue
Block a user