修正了逻辑,使 TPV 能够正常编译

This commit is contained in:
TermiNexus committed 2026-08-03 02:00:49 +08:00
1 parent 4e17365b76
commit 0a10b20dde
24 files changed
+2718 -1985

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
"""非阻塞式 Windows Toast 通知工具。
用法:
python Notify.py "标题(任务事项内容)" ["正文(可选)"]
替代旧的阻塞式 `msg *` 弹窗,通知右下角弹出后自动消失,无需手动点击。
"""
import subprocess
import sys
def SendToast(Title: str, Body: str = ""):
"""发送一条非阻塞式 Windows Toast 通知(Balloon Tip)。
参数:
Title: 通知标题,即"本次完成的任务事项内容",用于识别是谁完成了什么任务。
Body: 通知正文,可省略。
"""
# 转义 PowerShell 单引号,防止任务内容中的特殊字符破坏脚本
# BalloonTipText 不能为空,Body 省略时用默认正文
TitleEsc = Title.replace("'", "''")
BodyEsc = (Body if Body else "任务完成").replace("'", "''")
PsScript = (
"Add-Type -AssemblyName System.Windows.Forms; "
"Add-Type -AssemblyName System.Drawing; "
"$n = New-Object System.Windows.Forms.NotifyIcon; "
"$n.Icon = [System.Drawing.SystemIcons]::Information; "
"$n.BalloonTipIcon = 'Info'; "
"$n.BalloonTipTitle = '{0}'; "
"$n.BalloonTipText = '{1}'; "
"$n.Visible = $true; "
"$n.ShowBalloonTip(5000); "
"Start-Sleep -Milliseconds 6000; "
"$n.Dispose()"
).format(TitleEsc, BodyEsc)
try:
subprocess.run(
["powershell", "-NoProfile", "-WindowStyle", "Hidden", "-Command", PsScript],
check=True,
timeout=15,
)
except Exception as Ex:
sys.stderr.write("Notify failed: %s\n" % Ex)
sys.exit(1)
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.stderr.write("Usage: python Notify.py <Title> [Body]\n")
sys.exit(2)
SendToast(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "")
+12 -9
View File
@@ -1,5 +1,5 @@
更复杂的 泛型
函数装饰器
复杂原始(仿Python)函数装饰器
# main 收集(和 导入模块的自动执行)
元类型
# @p.set
@@ -7,24 +7,26 @@
崩溃/返回作用域 回调
# 假鸭子
# f-string 自动 snprintf
__doc__
自动索引
testcheck默认中文
# __doc__(后续需完善)
# 自动索引
# testcheck默认中文
vdebug 工具和 vsdt 工具
多态 ops 允许单个函数拥有装饰器(可修改,走函数指针)
协程关键字支持
with 出入多态
哈希表
# 哈希表
内联快速迭代器
出栈调用函数
构造函数隐式参数
# 构造函数隐式参数
小数组直接栈上创建+ i in [xxx]
字符串索引
# 字符串索引
单 @t.Object
单函数 @t.CVTable
import 自动执行代码
限制全局 import 符号到局部(其他文件import而本文件没import,但是仍然生效不报错)
生成器表达式
await 表达式(平台无关协程支持)
# 统一 mpool 和 mbuddy 接口
MCViper after 自举
@@ -35,4 +37,5 @@ init_set 构造
不在乎编译器时间的大小优化(无关符号剔除)
给 linkedlist 库改成 node 库,或者拆分 linkedlist 库
TPV 的 typedef 名是硬编码的,后期尝试修正
TPV 的 typedef 名是硬编码的,后期尝试修正
TPV 再次支持泛型能力检查和字节序
+1 -1
View File
@@ -1 +1 @@
{"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": "60b1f1f83634820e", "mtime": 1785470742.1546993, "size": 12673}, "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": "0fd87ff8da897c9b", "mtime": 1785478447.198817, "size": 25107}, "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": "8a88001814aa6e7b", "mtime": 1785485408.946777, "size": 10469}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesClassDef.vp": {"sha1": "07093bc887a35256", "mtime": 1785478535.6808052, "size": 145619}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesEnum.vp": {"sha1": "f05b14a2ad5767a7", "mtime": 1784741624.7278736, "size": 8520}, "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": "b70057095779b5be", "mtime": 1785482646.5378678, "size": 281321}, "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": 1785482062.1941507, "size": 48438}, "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\\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": "f09b2f4a0f9d053e", "mtime": 1785426809.706652, "size": 47907}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesTranslator.vp": {"sha1": "decd2fdd82387662", "mtime": 1785481813.1345608, "size": 23666}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Handles\\HandlesType.vp": {"sha1": "735fcd4c340edd2d", "mtime": 1785470195.0236213, "size": 79666}, "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", "mtime": 1785424554.7031634, "size": 13067}, "D:\\Users\\TermiNexus\\Desktop\\TransPyC\\TransPyV\\App\\lib\\core\\Phase1.vp": {"sha1": "8a526c65749808c5", "mtime": 1785470Line truncated
{"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
+15 -14
View File
@@ -1,79 +1,80 @@
0029b86ca4ba3c8a:lib/core/BuildPipeline.vp
067c78e9f121dce3:includes/w32\win32process.vp
06f53cc594b4ac6c:includes/w32\win32sync.vp
07093bc887a35256:lib/core/Handles/HandlesClassDef.vp
0bae3da2213d51e9:lib/core/StubMerger.vp
0c67644125bea0fd:includes/sys.vp
0d60272ffec7421e:lib/core/Handles/HandlesAugAssign.vp
0df65b8ed15664b0:includes/hashlib\__sha1.vp
0f9622f83dd1f680:lib/core/StubMerger.vp
0fd87ff8da897c9b:lib/core/Handles/HandlesAssign.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
3ed8c578036234a7:includes/viperlib.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
60b1f1f83634820e:lib/StubGen/VpiReader.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
735fcd4c340edd2d:lib/core/Handles/HandlesType.vp
7cadfe07e983fd90:includes/_list.vp
874bac141c97bae9:includes/llvmlite\__function.vp
8a526c65749808c5:lib/core/Phase1.vp
8a88001814aa6e7b:lib/core/Handles/HandlesBody.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
b70057095779b5be:lib/core/Handles/HandlesExprCall.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
ca40915f11b8b6ad:includes/memhub.vp
decd2fdd82387662:lib/core/Handles/HandlesTranslator.vp
d064df0bb07fe1ff:lib/core/Handles/HandlesTranslator.vp
d539c830f47d8334:lib/core/Handles/HandlesStruct.vp
d8379d695f0ce7ea:lib/core/Handles/HandlesEnum.vp
e217def267d3d4a8:includes/ast\lexer.vp
e4eb57e8026bccc7:includes/llvmlite\__builder.vp
ea374464a0b93230:lib/core/Handles/HandlesVar.vp
ebe9603dbffb6a35:lib/core/Handles/HandlesExpr.vp
ede39cea216a347e:lib/core/Handles/HandlesExprOps.vp
edfb76eb5b11cb51:lib/StubGen/Converter.vp
f05b14a2ad5767a7:lib/core/Handles/HandlesEnum.vp
f09b2f4a0f9d053e:lib/core/Handles/HandlesStruct.vp
f30a3b2d5f6bf092:main.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
Binary file not shown.
+84
View File
@@ -0,0 +1,84 @@
# -*- 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')
+2
View File
@@ -7,6 +7,8 @@ import os
import queue
import time
class ConsoleApp:
def __init__(self, root, args):
self.root = root
+1 -1
View File
@@ -7,7 +7,7 @@ import stdio
from linkedlist import GSListNode, GSList
from .__types import LLVMType, TypePrint
from .__values import Value, new_value, SSAValue
from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote
from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote, block_insert_text_before_terminator
# ============================================================
# IRBuilder: 游标式 IR 指令发射器
+8 -3
View File
@@ -4,6 +4,7 @@ import string
import atom
import viperio
import stdio
import sys
# ============================================================
# memhub - Unified memory management library
@@ -430,11 +431,15 @@ class MemBuddy(MemManager):
c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr))
result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr)
if result is None:
# Allocation failure: print memory usage statistics
# Allocation failure: print memory usage statistics and exit with OOM
fb: t.CSizeT = self.free_bytes()
ub: t.CSizeT = self.usable_size - fb
stdio.printf("[MEM-FAIL] alloc(%zu) failed: total=%zu used=%zu free=%zu free_blocks=%zu\n",
size, self.usable_size, ub, fb, self.free_count())
stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n")
stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size)
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)
self._unlock()
return result
+1377 -1376
View File
File diff suppressed because it is too large. Load diff
+21 -1
View File
@@ -483,10 +483,30 @@ class EvalContext:
self.translator: Any = translator
def lookup_name(self, name: str) -> Optional[Any]:
"""查找 Name 节点的值:define_constants → SymbolTable → 平台宏"""
"""查找 Name 节点的值:define_constants → SymbolTable → 平台宏
治本修复:不再把 module.globals 的 initializer 当常量返回。
CDefine 不创建 LLVM global(不在 module.globals),仅可变全局变量在
module.globals 中;把可变全局的 initializer 当编译期常量会让
range(_sha1_store_count) 等读取处求值成初始值 0 而不生成 load。
CDefine 通过下方 _define_constants 查询返回常量,双点 bug 不复发。
"""
# 1. Gen._define_constants
if self.Gen and name in self.Gen._define_constants:
val: Any = self.Gen._define_constants[name]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 通过
# 共享 _define_constants 覆盖本模块常量
# (VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖导致双点符号 bug)
_gvar: Any = None
try:
if hasattr(self.Gen, 'module') and name in self.Gen.module.globals:
_gvar = self.Gen.module.globals[name]
except Exception:
_gvar = None
if _gvar is not None and getattr(_gvar, 'initializer', None) is not None:
_init: Any = _gvar.initializer
if hasattr(_init, 'constant') and isinstance(_init.constant, (int, float)):
val = _init.constant
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
+17 -12
View File
@@ -286,18 +286,23 @@ class AssignHandle(BaseHandle):
Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name}
return
if VarName in Gen.global_vars:
if VarName in Gen.module.globals:
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
Gen._store(Value, GVar)
Gen.variables[VarName] = GVar
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
Gen.var_struct_class[VarName] = CN
elif VarName in Gen.variables and Gen.variables[VarName] is not None:
Gen._store(Value, Gen.variables[VarName])
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
GVar: ir.GlobalVariable
if VarName not in Gen.module.globals:
_gv_type: ir.Type = Value.type if isinstance(Value.type, (ir.IntType, ir.PointerType)) else ir.IntType(64)
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
GVar.initializer = ir.Constant(_gv_type, None) if isinstance(_gv_type, ir.PointerType) else ir.Constant(_gv_type, 0)
else:
GVar = Gen.module.globals[VarName]
Gen._store(Value, GVar)
Gen.variables[VarName] = GVar
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee)
if found:
CN: str = found[0]
ST: ir.Type = found[1]
Gen.var_struct_class[VarName] = CN
return
if VarName in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[VarName]
+12 -12
View File
@@ -87,8 +87,16 @@ class AugAssignHandle(BaseHandle):
if isinstance(Node.target, ast.Name):
VarName: str = Node.target.id
Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op)
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: ir.GlobalVariable = Gen.module.globals[VarName]
if VarName in Gen.global_vars:
# 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局
# (注解无初始值的全局变量),此处自动创建零初始化全局变量
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)
GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName)
GVar.initializer = ir.Constant(_gv_type, 0)
else:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
OldVal: ir.Value = Gen._load(GVar, name=VarName)
NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned)
@@ -96,22 +104,14 @@ class AugAssignHandle(BaseHandle):
return
if VarName in Gen._reg_values:
OldVal: ir.Value = Gen._reg_values[VarName]
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[VarName] = var
del Gen._reg_values[VarName]
if VarName in Gen._direct_values:
OldVal: ir.Value = Gen._direct_values.pop(VarName)
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=VarName)
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[VarName] = var
if Gen.builder.block.is_terminated:
return
+10
View File
@@ -657,6 +657,16 @@ class BaseHandle:
ArrayCount = sym_info.value
if ArrayCount == 1 and count_node.id in Gen._define_constants:
def_val: Any = Gen._define_constants[count_node.id]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
try:
if hasattr(Gen, 'module') and count_node.id in Gen.module.globals:
_gv: Any = Gen.module.globals[count_node.id]
if getattr(_gv, 'initializer', None) is not None:
_iv: Any = _gv.initializer
if hasattr(_iv, 'constant') and isinstance(_iv.constant, int):
def_val = _iv.constant
except Exception:
pass
if isinstance(def_val, int):
ArrayCount = def_val
return ArrayCount
+504 -492
View File
@@ -1,493 +1,505 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.constants.config import mode as _config_mode
from lib.includes.t import CTypeRegistry as _CR
class ExprHandle(BaseHandle):
# list 元素类型 → (字节大小, LLVM 元素类型) 映射表
# 用于 _HandleListLlvm 中 alloc_size / byte_offset / elem_ptr 类型统一查表,
# 消除原代码三处重复的 if-elif 链。
_ELEM_TYPE_INFO: dict[str, tuple[int, ir.Type]] = {
'i8': (1, ir.IntType(8)),
'i16': (2, ir.IntType(16)),
'i32': (4, ir.IntType(32)),
'float': (4, ir.FloatType()),
'double': (8, ir.DoubleType()),
}
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node: ast.AST, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
return self._HandleNameLlvm(Node, VarType)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node: ast.List, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
elements: list[ast.expr] = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len: int = len(elements)
elem_type: str = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
match: re.Match | None = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_str: str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size: int = array_len
elem_info: tuple[int, ir.Type] = self._ELEM_TYPE_INFO.get(elem_type, (1, ir.IntType(8)))
elem_size: int = elem_info[0]
elem_llvm_type: ir.Type = elem_info[1]
alloc_size *= elem_size
malloc_fn: Any = None
malloc_arg_type: ir.IntType = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype: Any = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
Gen.functions['malloc'] = malloc_fn
except Exception: # 回退:malloc 函数创建失败时返回 null
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr: Any = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr: Any = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset: int = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
ptr_as_int: Any = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val: Any = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr: Any = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type in ('float', 'double'):
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(elem_llvm_type), name=f"list_{elem_type}_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node: ast.Constant, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Value: Any = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
resolved: Any = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls: type = resolved[0] if isinstance(resolved, tuple) else resolved
inst: Any = ctype_cls()
size: int = getattr(inst, 'Size', 32)
is_unsigned: bool = getattr(inst, 'IsSigned', True) is False
mask: int = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match: re.Match | None = re.match(r'^i(\d+)$', VarType)
if llvm_match:
width: int = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide: bool = getattr(Node, 'kind', None) == 'u'
# 引号类型推断:单引号单字符 → i8,双引号/多字符/三重 → i8*,空 → 0(None)
quote_char: str | None = None
is_triple: bool = False
if not is_wide:
col_offset: int = getattr(Node, 'col_offset', 0)
node_lineno: int = getattr(Node, 'lineno', 0)
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
# 因此在 lineno 和 lineno-1 两行中查找引号
for try_lineno in (node_lineno, node_lineno - 1):
source_line: str | None = Gen._get_source_line(try_lineno)
if source_line and col_offset < len(source_line):
ch: str = source_line[col_offset]
if ch in ("'", '"'):
quote_char = ch
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
is_triple = True
break
# 空字符串 → 创建指向 \0 的全局变量 (而非 null, 避免 strcmp 解引用空指针崩溃)
# 走与非空字符串相同的路径, 由下方 else 分支处理
# 单引号单字符(非三重)→ i8
is_char_literal: bool = (not is_triple) and (quote_char == "'") and (len(Value) == 1) and not is_wide
if is_char_literal:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass # 类型不匹配:目标是 ptr 但值是 char,走 string 路径
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
resolved = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = re.match(r'^i(\d+)$', VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
else:
# 无类型提示:单引号单字符默认为 i8
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value: str = Value + '\x00'
wide_chars: list[int] = [ord(c) for c in str_value]
target_count: int = len(wide_chars)
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(16), target_count)
gv_name: str = f"str_const_{Gen.string_const_counter}"
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr: Any = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes: bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
VarName: str = Node.id
# [CD] 诊断:仅对关键常量输出(FOREGROUND_*, BACKGROUND_*, STD_*, *HANDLE*)
import sys as _sys
_is_cd_key: bool = isinstance(VarName, str) and (VarName.startswith('FOREGROUND_') or VarName.startswith('BACKGROUND_') or 'STD_' in VarName or 'HANDLE' in VarName)
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
if VarName in define_constants:
val: Any = define_constants[VarName]
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
# 如果 _define_constants 中没有,尝试从符号表查找
if VarName not in define_constants:
try:
sym_info: Any = self.Trans.SymbolTable.lookup(VarName)
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
val = sym_info.DefineValue
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in SymbolTable val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
# Use VarType hint if available
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
elif _is_cd_key:
print(f"[CD] lookup: '{VarName}' NOT in SymbolTable", file=_sys.stderr, flush=True)
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 治本修复:如果符号表也没有,回退查询 _all_define_constants
# _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取,
# 包含跨模块导入的 CDefine 常量(如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE)
if VarName not in define_constants:
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
if VarName in all_dc:
val: Any = all_dc[VarName]
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _all_define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
elif _is_cd_key:
print(f"[CD] lookup: '{VarName}' NOT found in ANY CDefine table", file=_sys.stderr, flush=True)
# 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: Any = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
# 防御性恢复:对于 double-pointer(如 ndarray**,pointee 是 PointerType)
# 或其他非结构体类型,若 global_struct_class 已记录该变量的类名,
# 也恢复 var_struct_class。这确保方法调用能查找到正确的特化类
# (如 ndarray[double]),而非 fallback 到 opaque 基础类型。
if VarName in Gen.global_struct_class and VarName not in Gen.var_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
# 大端局部变量:读取时 bswap 还原
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
return loaded
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: Any = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
# 治本修复:方法名为 _get_var_ptr(小写),原 GetVarPtr 不存在会抛 AttributeError。
# 当 self 未注册到 variables 时(如 opaque struct 参数走了 else 分支),
# 通过 _get_var_ptr 兜底返回 None,由调用方处理。
SelfPtr: ir.Value | None = Gen._get_var_ptr('self')
if SelfPtr is not None:
return SelfPtr
# 最终兜底:若 _get_var_ptr 返回 None(self 既不在 _reg_values 也不在 variables),
# 直接返回函数参数本身(LLVM Argument)。这避免了 AttributeError 导致的异常路径。
for arg in getattr(Gen.func, 'args', []):
if getattr(arg, 'name', None) == 'self':
return arg
return ir.Constant(ir.IntType(32), 0)
if Gen._has_function(VarName):
func: Any = Gen._get_function(VarName)
if func:
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
if VarName in Gen.class_methods:
return ir.Constant(ir.IntType(8).as_pointer(), None)
if VarName == 'True' or VarName == 'False':
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
if SymInfo:
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
MangledName: str = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g: Any = Gen.module.globals[MangledName]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
for sha1 in Gen.ModuleSha1Map.values():
prefixed: str = f"{sha1}.{VarName}"
if prefixed in Gen.module.globals:
g = Gen.module.globals[prefixed]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
t_c_imported: dict[str, tuple[str, str]] = getattr(self.Trans, '_t_c_imported_names', {})
if VarName in t_c_imported:
src_module: str
src_name: str
src_module, src_name = t_c_imported[VarName]
virtual_attr: ast.Attribute = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import ast
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.constants.config import mode as _config_mode
from lib.includes.t import CTypeRegistry as _CR
class ExprHandle(BaseHandle):
# list 元素类型 → (字节大小, LLVM 元素类型) 映射表
# 用于 _HandleListLlvm 中 alloc_size / byte_offset / elem_ptr 类型统一查表,
# 消除原代码三处重复的 if-elif 链。
_ELEM_TYPE_INFO: dict[str, tuple[int, ir.Type]] = {
'i8': (1, ir.IntType(8)),
'i16': (2, ir.IntType(16)),
'i32': (4, ir.IntType(32)),
'float': (4, ir.FloatType()),
'double': (8, ir.DoubleType()),
}
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node: ast.AST, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
return self._HandleNameLlvm(Node, VarType)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node: ast.List, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
elements: list[ast.expr] = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len: int = len(elements)
elem_type: str = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
match: re.Match | None = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
if match:
type_str: str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size: int = array_len
elem_info: tuple[int, ir.Type] = self._ELEM_TYPE_INFO.get(elem_type, (1, ir.IntType(8)))
elem_size: int = elem_info[0]
elem_llvm_type: ir.Type = elem_info[1]
alloc_size *= elem_size
malloc_fn: Any = None
malloc_arg_type: ir.IntType = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype: Any = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc')
Gen.functions['malloc'] = malloc_fn
except Exception: # 回退:malloc 函数创建失败时返回 null
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr: Any = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr: Any = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
byte_offset: int = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
ptr_as_int: Any = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64))
new_ptr_val: Any = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset))
if elem_type == 'i32':
elem_ptr: Any = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8)))
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}")
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}")
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type in ('float', 'double'):
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(elem_llvm_type), name=f"list_{elem_type}_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node: ast.Constant, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Value: Any = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
resolved: Any = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls: type = resolved[0] if isinstance(resolved, tuple) else resolved
inst: Any = ctype_cls()
size: int = getattr(inst, 'Size', 32)
is_unsigned: bool = getattr(inst, 'IsSigned', True) is False
mask: int = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match: re.Match | None = re.match(r'^i(\d+)$', VarType)
if llvm_match:
width: int = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide: bool = getattr(Node, 'kind', None) == 'u'
# 引号类型推断:单引号单字符 → i8,双引号/多字符/三重 → i8*,空 → 0(None)
quote_char: str | None = None
is_triple: bool = False
if not is_wide:
col_offset: int = getattr(Node, 'col_offset', 0)
node_lineno: int = getattr(Node, 'lineno', 0)
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
# 因此在 lineno 和 lineno-1 两行中查找引号
for try_lineno in (node_lineno, node_lineno - 1):
source_line: str | None = Gen._get_source_line(try_lineno)
if source_line and col_offset < len(source_line):
ch: str = source_line[col_offset]
if ch in ("'", '"'):
quote_char = ch
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
is_triple = True
break
# 空字符串 → 创建指向 \0 的全局变量 (而非 null, 避免 strcmp 解引用空指针崩溃)
# 走与非空字符串相同的路径, 由下方 else 分支处理
# 单引号单字符(非三重)→ i8
is_char_literal: bool = (not is_triple) and (quote_char == "'") and (len(Value) == 1) and not is_wide
if is_char_literal:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass # 类型不匹配:目标是 ptr 但值是 char,走 string 路径
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
resolved = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = re.match(r'^i(\d+)$', VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
else:
# 无类型提示:单引号单字符默认为 i8
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value: str = Value + '\x00'
wide_chars: list[int] = [ord(c) for c in str_value]
target_count: int = len(wide_chars)
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(16), target_count)
gv_name: str = f"str_const_{Gen.string_const_counter}"
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr: Any = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes: bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
VarName: str = Node.id
# [CD] 诊断:仅对关键常量输出(FOREGROUND_*, BACKGROUND_*, STD_*, *HANDLE*)
import sys as _sys
_is_cd_key: bool = isinstance(VarName, str) and (VarName.startswith('FOREGROUND_') or VarName.startswith('BACKGROUND_') or 'STD_' in VarName or 'HANDLE' in VarName)
# 治本修复:不把 module.globals 的 initializer 注入 _define_constants。
# 原因:CDefine(t.CDefine 注解)在 AnnAssign/Assign 处理时已注册到
# _define_constants 且不创建 LLVM global(不在 module.globals);
# module.globals 里全是可变全局变量(如 _sha1_store_count,有 += 写入),
# 若把其 initializer 当常量传播,会导致 range(_sha1_store_count) 被求值成
# range(0)、printf 印 0 等问题(读取处不生成 load)。
# CDefine 的本模块优先靠下方 _define_constants 查询保证,双点 bug 不复发。
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
# 治本防护:module.globals 里的都是可变全局变量(CDefine 不创建 LLVM global,
# 仅注册到 _define_constants)。可变全局有 += 等写入,不能当常量传播,
# 跳过 _define_constants 查询,直接走下方 variables/global_vars/module.globals 的 load。
if VarName in define_constants and not (hasattr(Gen, 'module') and VarName in Gen.module.globals):
val: Any = define_constants[VarName]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 通过
# 共享 _define_constants 覆盖本模块常量
# (VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖导致双点符号 bug)
_gvar: Any = None
try:
if hasattr(Gen, 'module') and VarName in Gen.module.globals:
_gvar = Gen.module.globals[VarName]
except Exception:
_gvar = None
if _gvar is not None and getattr(_gvar, 'initializer', None) is not None:
_init: Any = _gvar.initializer
if isinstance(_init, ir.Constant) and isinstance(_init.constant, (int, float, str)):
val = _init.constant
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
# Use VarType hint if available to avoid unnecessary type mismatch
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
# 治本修复(方案C):CDefine 不通过共享 SymbolTable 跨模块裸名共享。
# 此处不再消费 SymbolTable 中的 IsDefine 符号,避免其他模块 CDefine
# 覆盖本模块同名全局变量(VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖)。
# 本模块 CDefine 已在步骤1(_define_constants)解析;
# 跨模块 CDefine 通过 _RegisterFromImportAliases 显式导入注册到 _define_constants。
if VarName not in define_constants:
try:
sym_info: Any = self.Trans.SymbolTable.lookup(VarName)
if _is_cd_key and sym_info and sym_info.IsDefine:
print(f"[CD] lookup: '{VarName}' skipped in SymbolTable (CDefine not cross-module)", file=_sys.stderr, flush=True)
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 治本修复:如果符号表也没有,回退查询 _all_define_constants
# _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取,
# 包含跨模块导入的 CDefine 常量(如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE)
if VarName not in define_constants and VarName not in Gen.variables and not (hasattr(Gen, 'module') and VarName in Gen.module.globals):
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
if VarName in all_dc:
val: Any = all_dc[VarName]
if _is_cd_key:
print(f"[CD] lookup: '{VarName}' found in _all_define_constants val={val}", file=_sys.stderr, flush=True)
if isinstance(val, int):
if VarType is not None and isinstance(VarType, ir.IntType):
return ir.Constant(VarType, val & ((1 << VarType.width) - 1))
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
elif _is_cd_key:
print(f"[CD] lookup: '{VarName}' NOT found in ANY CDefine table", file=_sys.stderr, flush=True)
# 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: Any = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
# 防御性恢复:对于 double-pointer(如 ndarray**,pointee 是 PointerType)
# 或其他非结构体类型,若 global_struct_class 已记录该变量的类名,
# 也恢复 var_struct_class。这确保方法调用能查找到正确的特化类
# (如 ndarray[double]),而非 fallback 到 opaque 基础类型。
if VarName in Gen.global_struct_class and VarName not in Gen.var_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
# 大端局部变量:读取时 bswap 还原
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
return loaded
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: Any = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
# 治本修复:方法名为 _get_var_ptr(小写),原 GetVarPtr 不存在会抛 AttributeError。
# 当 self 未注册到 variables 时(如 opaque struct 参数走了 else 分支),
# 通过 _get_var_ptr 兜底返回 None,由调用方处理。
SelfPtr: ir.Value | None = Gen._get_var_ptr('self')
if SelfPtr is not None:
return SelfPtr
# 最终兜底:若 _get_var_ptr 返回 None(self 既不在 _reg_values 也不在 variables),
# 直接返回函数参数本身(LLVM Argument)。这避免了 AttributeError 导致的异常路径。
for arg in getattr(Gen.func, 'args', []):
if getattr(arg, 'name', None) == 'self':
return arg
return ir.Constant(ir.IntType(32), 0)
if Gen._has_function(VarName):
func: Any = Gen._get_function(VarName)
if func:
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
if VarName in Gen.class_methods:
return ir.Constant(ir.IntType(8).as_pointer(), None)
if VarName == 'True' or VarName == 'False':
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
if SymInfo:
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
MangledName: str = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g: Any = Gen.module.globals[MangledName]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
for sha1 in Gen.ModuleSha1Map.values():
prefixed: str = f"{sha1}.{VarName}"
if prefixed in Gen.module.globals:
g = Gen.module.globals[prefixed]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
t_c_imported: dict[str, tuple[str, str]] = getattr(self.Trans, '_t_c_imported_names', {})
if VarName in t_c_imported:
src_module: str
src_name: str
src_module, src_name = t_c_imported[VarName]
virtual_attr: ast.Attribute = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
return ir.Constant(ir.IntType(32), 0)
+11 -1
View File
@@ -281,6 +281,11 @@ class ExprAsmHandle(BaseHandle):
def _mangle_asm_calls(self, template: str) -> str:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
sha1: str = getattr(Gen, 'module_sha1', '')
# DDEBUG: 检测 module_sha1 是否带尾随点(双点 bug 根因拦截)
if sha1 and sha1.endswith('.'):
import sys as _dbg_sys
print(f"[DDEBUG_ASM] module_sha1 带尾随点: sha1='{sha1}' len={len(sha1)} template='{template[:80]}'", file=_dbg_sys.stderr)
_dbg_sys.exit(1)
if not sha1:
return template
@@ -290,13 +295,18 @@ class ExprAsmHandle(BaseHandle):
if func_name.lower() in self._X86_REGISTERS:
return m.group(0)
mangled: str = Gen._mangle_func_name(func_name)
# DDEBUG: 检测 mangled 是否含双点(双点 bug 根因拦截)
if '..' in mangled:
import sys as _dbg_sys
print(f"[DDEBUG_ASM] mangled 含双点: func='{func_name}' mangled='{mangled}' sha1='{sha1}'", file=_dbg_sys.stderr)
_dbg_sys.exit(1)
if '.' in mangled:
return f'{prefix}\\22{mangled}\\22'
return f"{prefix}{mangled}"
return re.sub(r'(call\s+)(\w+)', replace_call, template)
def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value:
def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
input_ops: list[Any] = []
+9
View File
@@ -1873,6 +1873,15 @@ class ExprCallHandle(BaseHandle):
def _HandleClosureCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
Gen = self.Trans.LlvmGen
func = Gen.functions.get(FuncName)
# DDEBUG: 检测 func.name 含双点(说明 ir.Function 已被错误注册为双点名字)
if func is not None and '..' in getattr(func, 'name', ''):
import sys
sys.stderr.write(f"[DDEBUG] _HandleClosureCallLlvm DOUBLE-DOT func.name='{func.name}' FuncName='{FuncName}'\n")
sys.stderr.write(f"[DDEBUG] Gen.functions keys for '{FuncName}': {[k for k in list(Gen.functions.keys()) if '6ddf' in k or k == FuncName][:20]}\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
if not func:
if FuncName in self.Trans.FunctionDefCache:
FuncDef = self.Trans.FunctionDefCache[FuncName]
+10
View File
@@ -82,6 +82,16 @@ class IfHandle(BaseHandle):
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if hasattr(Gen, '_define_constants') and name in Gen._define_constants:
val: int | float | None = Gen._define_constants[name]
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖
try:
if hasattr(Gen, 'module') and name in Gen.module.globals:
_gv: Any = Gen.module.globals[name]
if getattr(_gv, 'initializer', None) is not None:
_iv: Any = _gv.initializer
if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)):
val = _iv.constant
except Exception:
pass
if isinstance(val, (int, float)):
return val
info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name)
+12 -8
View File
@@ -907,17 +907,21 @@ class ImportHandle(BaseHandle):
return
if IsCDefine:
# CDefine 宏不生成 LLVM 全局变量,只注册到 SymbolTable
# 引用时会直接替换为立即数
# CDefine 宏不生成 LLVM 全局变量
# 治本修复(方案C):裸名只注册到本模块 _define_constants,
# 不再注册到跨模块共享的 SymbolTable,避免同名 CDefine 污染其他模块的全局变量
# (如 Phase1.SHA1_LEN=17 覆盖 VpiReader.SHA1_LEN=16 导致双点链接错误)。
# 跨模块导入通过 _RegisterFromImportAliases 查带前缀全名后注册到本模块 _define_constants。
DefineValue = None
if Node.value:
DefineValue = self._ExtractConstValue(Node.value)
# 注册不带前缀的键名(例如 Z_NO_COMPRESSION)
# 但要先检查:如果符号已经存在且是 typedef,不覆盖它
existing = self.Trans.SymbolTable.lookup(VarName)
if not (existing and existing.IsTypedef and existing.OriginalType):
self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, ModulePath or 'unknown')
# 如果提供了模块名,也注册带模块前缀的键名
# 仅本模块 CDefine 注册到 _define_constants(供 _HandleNameLlvm 步骤1 查找)
if module_name is None and DefineValue is not None:
define_constants = vars(Gen).setdefault('_define_constants', {})
if VarName not in define_constants:
define_constants[VarName] = DefineValue
# 如果提供了模块名,注册带模块前缀的全名到 SymbolTable
# (供 _RegisterFromImportAliases 的 from X import Y 显式导入查找)
if module_name:
FullName = f"{module_name}.{VarName}"
existing_full = self.Trans.SymbolTable.lookup(FullName)
+52 -53
View File
@@ -1,54 +1,53 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import llvmlite.ir as ir
class WhileHandle(BaseHandle):
def _HandleWhileLlvm(self, Node: ast.While) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if Gen._direct_values:
for var_name in list(Gen._direct_values.keys()):
OldVal: ir.Value = Gen._direct_values.pop(var_name)
if var_name not in Gen.variables or Gen.variables.get(var_name) is None:
saved_block: ir.Block = Gen.builder.block
entry_block: ir.Block = Gen.func.entry_basic_block
Gen.builder.position_at_start(entry_block)
var: ir.AllocaInstr = Gen.builder.alloca(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.builder.position_at_end(saved_block)
Gen.variables[var_name] = var
CondBB: ir.Block = Gen.func.append_basic_block(name="while.cond")
BodyBB: ir.Block = Gen.func.append_basic_block(name="while.body")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="while.else") if Node.orelse else None
AfterBB: ir.Block = Gen.func.append_basic_block(name="while.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(CondBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Cond: ir.Value | None = self.HandleExprLlvm(Node.test)
if Cond:
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="whilecond")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.Handles.HandlesBase import BaseHandle
import llvmlite.ir as ir
class WhileHandle(BaseHandle):
def _HandleWhileLlvm(self, Node: ast.While) -> None:
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
if Gen._direct_values:
for var_name in list(Gen._direct_values.keys()):
OldVal: ir.Value = Gen._direct_values.pop(var_name)
if var_name not in Gen.variables or Gen.variables.get(var_name) is None:
# 用 _allocaEntry 在入口块开头插入 alloca,然后在当前 builder
# 位置生成 store。避免 position_at_start 导致 store 插入到
# 入口块开头(可能在 va_list_ptr 等 bitcast 定义之前,违反支配性)。
var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=var_name)
Gen._store(OldVal, var)
Gen.variables[var_name] = var
CondBB: ir.Block = Gen.func.append_basic_block(name="while.cond")
BodyBB: ir.Block = Gen.func.append_basic_block(name="while.body")
ElseBB: ir.Block | None = Gen.func.append_basic_block(name="while.else") if Node.orelse else None
AfterBB: ir.Block = Gen.func.append_basic_block(name="while.end")
Gen.loop_break_targets.append(AfterBB)
Gen.loop_continue_targets.append(CondBB)
Gen.builder.branch(CondBB)
Gen.builder.position_at_start(CondBB)
Cond: ir.Value | None = self.HandleExprLlvm(Node.test)
if Cond:
if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1:
if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)):
Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond")
else:
Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="whilecond")
if not Gen.builder.block.is_terminated:
Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB)
else:
if not Gen.builder.block.is_terminated:
Gen.builder.branch(ElseBB if ElseBB else AfterBB)
Gen.builder.position_at_start(BodyBB)
self.HandleBodyLlvm(Node.body)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(CondBB)
Gen.loop_break_targets.pop()
Gen.loop_continue_targets.pop()
if ElseBB:
Gen.builder.position_at_start(ElseBB)
self.HandleBodyLlvm(Node.orelse)
if not Gen.builder.block.is_terminated:
Gen.builder.branch(AfterBB)
Gen.builder.position_at_start(AfterBB)
+28 -2
View File
@@ -595,6 +595,14 @@ class BaseGenMixin:
return self._find_function(name) is not None
def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function:
# DDEBUG: 检测 mangled_name 含双点(不应到达这里)
if '..' in mangled_name:
import sys
sys.stderr.write(f"[DDEBUG] _get_or_declare_function DOUBLE-DOT mangled_name='{mangled_name}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
g = self.module.globals.get(mangled_name)
if g and isinstance(g, ir.Function):
return g
@@ -605,6 +613,14 @@ class BaseGenMixin:
return func
def _mangle_func_name(self, name: str, module_name: str | None = None) -> str:
# DDEBUG: 检测即将产生双点的情况,立即打印并终止
if name.startswith('.') or (module_name and module_name.endswith('.') and len(module_name) > 0):
import sys
sys.stderr.write(f"[DDEBUG] _mangle_func_name LEADING-DOT name='{name}' module_name='{module_name}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=8)
sys.stderr.flush()
sys.exit(1)
if name in self._export_funcs and not module_name:
return name
if name in self._export_extern_funcs:
@@ -659,8 +675,18 @@ class BaseGenMixin:
if self._skip_mangle(name):
return name
if self.module_sha1:
return f"{self.module_sha1}.{name}"
return name
result = f"{self.module_sha1}.{name}"
else:
result = name
# DDEBUG: 检测返回结果中是否含双点
if '..' in result:
import sys
sys.stderr.write(f"[DDEBUG] _mangle_func_name RESULT-DOUBLE-DOT name='{name}' module_name='{module_name}' result='{result}'\n")
import traceback
traceback.print_stack(file=sys.stderr, limit=10)
sys.stderr.flush()
sys.exit(1)
return result
def _get_source_line(self, lineno: int) -> str | None:
if 0 < lineno <= len(self._current_source_lines):
View File
Whitespace-only changes.
+478
View File
@@ -0,0 +1,478 @@
===== 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
View File
@@ -0,0 +1 @@
===== Test Suite Complete =====