修正了逻辑,使 TPV 能够正常编译
This commit is contained in:
1 parent
4e17365b76
commit
0a10b20dde
24 files changed
+2718
-1985
No files matched your search
@@ -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 "")
|
||||
@@ -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 @@
|
||||
{"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
@@ -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.
@@ -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')
|
||||
@@ -7,6 +7,8 @@ import os
|
||||
import queue
|
||||
import time
|
||||
|
||||
|
||||
|
||||
class ConsoleApp:
|
||||
def __init__(self, root, args):
|
||||
self.root = root
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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)
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
@@ -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] = []
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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):
|
||||
|
||||
Whitespace-only changes.
+478
@@ -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 =====
|
||||
@@ -0,0 +1 @@
|
||||
===== Test Suite Complete =====
|
||||
Reference in new issue
Block a user