fix(Translator): 类体 CDefine 预扫描扩展 + CDefine 类型修复(i32)
- GenerateLlvmDirect 预扫描扩展到类体 AnnAssign,注册类体 CDefine 常量 (方法内裸名如 ISINSTANCE_CLASS_MAX 不再解析为 0) - t.py CDefine Size/IsSigned 覆盖为 32 位有符号,修复 stub 生成 void 类型 - 新增 Test/TpvIsinstanceTest(TPV 侧 isinstance 回归测试)
This commit is contained in:
1 parent
1b89225130
commit
9c2dc45c03
4 files changed
+197
-19
No files matched your search
@@ -0,0 +1,125 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
from t import CPtr, CInt, CExport
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TPV 侧 isinstance 内建函数测试(由 TransPyV.exe 编译)
|
||||
#
|
||||
# 验证 TPV 编译器生成的 isinstance IR:
|
||||
# 1. CVTable 自身 / 子类→基类
|
||||
# 2. 运行时多态(基类指针指向子类对象)
|
||||
# 3. 元组 (A, B)
|
||||
# 4. 多继承
|
||||
# 5. NoVTable 编译时静态判断
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ========== CVTable 继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class Animal:
|
||||
Name: str
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.Name = name
|
||||
|
||||
def speak(self) -> str:
|
||||
return "..."
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Dog(Animal):
|
||||
def speak(self) -> str:
|
||||
return "Woof"
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Cat(Animal):
|
||||
def speak(self) -> str:
|
||||
return "Meow"
|
||||
|
||||
|
||||
# ========== 多继承 ==========
|
||||
|
||||
@t.CVTable
|
||||
class A:
|
||||
a: CInt
|
||||
|
||||
def get_a(self) -> CInt:
|
||||
return self.a
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class B:
|
||||
b: CInt
|
||||
|
||||
def get_b(self) -> CInt:
|
||||
return self.b
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class AB(A, B):
|
||||
def __init__(self, a: CInt, b: CInt):
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
|
||||
# ========== NoVTable(编译时静态判断) ==========
|
||||
|
||||
@t.NoVTable
|
||||
class Plain:
|
||||
v: CInt
|
||||
|
||||
|
||||
def main() -> CInt | CExport:
|
||||
testcheck.begin("TpvIsinstanceTest: TPV 侧 isinstance 测试")
|
||||
|
||||
# --- 1. 自身类型 + 子类→基类 ---
|
||||
d: Dog | CPtr = Dog("dog")
|
||||
testcheck.check(isinstance(d, Dog) == 1, "isinstance(d, Dog) 自身 OK",
|
||||
"isinstance(d, Dog) FAILED")
|
||||
testcheck.check(isinstance(d, Animal) == 1, "isinstance(d, Animal) 子类→基类 OK",
|
||||
"isinstance(d, Animal) FAILED")
|
||||
testcheck.check(isinstance(d, Cat) == 0, "isinstance(d, Cat) 不匹配 OK",
|
||||
"isinstance(d, Cat) FAILED")
|
||||
|
||||
# --- 2. 运行时多态:基类指针指向子类对象 ---
|
||||
a: Animal | CPtr = (Animal | CPtr)(d)
|
||||
testcheck.check(isinstance(a, Dog) == 1,
|
||||
"isinstance(Animal*, Dog 对象) 运行时多态 OK",
|
||||
"isinstance(Animal*, Dog) FAILED")
|
||||
testcheck.check(isinstance(a, Animal) == 1,
|
||||
"isinstance(Animal*, Animal) 基类自身 OK",
|
||||
"isinstance(Animal*, Animal) FAILED")
|
||||
testcheck.check(isinstance(a, Cat) == 0,
|
||||
"isinstance(Animal*, Cat) 运行时 False OK",
|
||||
"isinstance(Animal*, Cat) FAILED")
|
||||
|
||||
# --- 3. 元组 ---
|
||||
testcheck.check(isinstance(d, (Cat, Dog)) == 1, "isinstance 元组命中 OK",
|
||||
"isinstance 元组 FAILED")
|
||||
testcheck.check(isinstance(d, (Cat, A)) == 0, "isinstance 元组未命中 OK",
|
||||
"isinstance 元组未命中 FAILED")
|
||||
|
||||
# --- 4. 多继承 ---
|
||||
ab: AB | CPtr = AB(1, 2)
|
||||
testcheck.check(isinstance(ab, A) == 1, "isinstance(AB, A) 多继承 OK",
|
||||
"isinstance(AB, A) FAILED")
|
||||
testcheck.check(isinstance(ab, B) == 1, "isinstance(AB, B) 多继承 OK",
|
||||
"isinstance(AB, B) FAILED")
|
||||
testcheck.check(isinstance(ab, Animal) == 0, "isinstance(AB, Animal) False OK",
|
||||
"isinstance(AB, Animal) FAILED")
|
||||
testcheck.check(ab.get_a() == 1 and ab.get_b() == 2, "AB 字段/方法正常 OK",
|
||||
"AB 字段/方法 FAILED")
|
||||
|
||||
# --- 5. NoVTable(编译时静态判断) ---
|
||||
p: Plain | CPtr = Plain()
|
||||
p.v = 42
|
||||
testcheck.check(isinstance(p, Plain) == 1, "isinstance NoVTable 编译时 OK",
|
||||
"isinstance NoVTable FAILED")
|
||||
testcheck.check(p.v == 42, "NoVTable 字段正常 OK", "NoVTable 字段 FAILED")
|
||||
|
||||
testcheck.ok("TPV 侧 isinstance 全部测试完成")
|
||||
return testcheck.end()
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "TpvIsinstanceTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"],
|
||||
"output": "TpvIsinstanceTest.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
@@ -74,30 +74,44 @@ class LlvmGeneratorMixin:
|
||||
# 使用 ConstEvaluator 处理 BinOp/UnaryOp/Name/Attribute/Call
|
||||
return ConstEvaluator.eval_with_symtab(node, self.SymbolTable)
|
||||
|
||||
def _is_cdefine_type(TypeInfo: CTypeInfo | None) -> bool:
|
||||
"""判断 CTypeInfo 是否对应 t.CDefine 注解"""
|
||||
return bool(TypeInfo and TypeInfo.BaseType and
|
||||
((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine))
|
||||
or isinstance(TypeInfo.BaseType, t.CDefine) or TypeInfo.IsDefine))
|
||||
|
||||
def _register_cdefine_constant(NameNode: ast.Name, Annotation: ast.expr, Value: ast.expr) -> None:
|
||||
"""注册 CDefine 编译期常量(_define_constants + SymbolTable)"""
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Annotation)
|
||||
if not _is_cdefine_type(TypeInfo):
|
||||
return
|
||||
val: int | str | float | None = _extract_const_value(Value)
|
||||
if val is not None:
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants: dict[str, int | str | float | bool] = {}
|
||||
Gen._define_constants[NameNode.id] = val
|
||||
existing = self.SymbolTable.lookup(NameNode.id)
|
||||
if not (existing and existing.IsTypedef and existing.OriginalType):
|
||||
sym_info: _CTypeInfo = _CTypeInfo()
|
||||
sym_info.IsDefine = True
|
||||
sym_info.DefineValue = val
|
||||
self.SymbolTable.insert(NameNode.id, sym_info)
|
||||
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
|
||||
# 治本修复:检查 BaseType 是否为 t.CDefine 实例/子类,或 IsDefine 标志
|
||||
# IsDefine 由 GetCTypeInfo 对 t.CDefine 注解自动设置
|
||||
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine) or TypeInfo.IsDefine):
|
||||
val: int | str | float | None = _extract_const_value(Node.value)
|
||||
import sys as _sys
|
||||
_nm = Node.target.id
|
||||
# [CD] 仅输出关键常量(FOREGROUND_*, STD_OUTPUT_HANDLE, BACKGROUND_*)
|
||||
if isinstance(_nm, str) and (_nm.startswith('FOREGROUND_') or _nm.startswith('BACKGROUND_') or 'STD_' in _nm or 'HANDLE' in _nm):
|
||||
print(f"[CD] extract: '{_nm}' IsDefine={TypeInfo.IsDefine} val={val}", file=_sys.stderr, flush=True)
|
||||
if val is not None:
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants: dict[str, int | str | float | bool] = {}
|
||||
Gen._define_constants[Node.target.id] = val
|
||||
existing = self.SymbolTable.lookup(Node.target.id)
|
||||
if not (existing and existing.IsTypedef and existing.OriginalType):
|
||||
sym_info: _CTypeInfo = _CTypeInfo()
|
||||
sym_info.IsDefine = True
|
||||
sym_info.DefineValue = val
|
||||
self.SymbolTable.insert(Node.target.id, sym_info)
|
||||
else:
|
||||
print(f"[CD] extract: WARN val is None for '{_nm}'", file=_sys.stderr, flush=True)
|
||||
if _is_cdefine_type(TypeInfo):
|
||||
_register_cdefine_constant(Node.target, Node.annotation, Node.value)
|
||||
elif isinstance(Node, ast.ClassDef):
|
||||
# 类体 CDefine 常量(2026-08-10):供方法内裸名(如 Mixin 的
|
||||
# ISINSTANCE_CLASS_MAX/MRO_MAX: t.CDefine = N)编译期解析为常量值。
|
||||
# 原预扫描只用 iter_child_nodes 扫顶层,类体常量不注册 → 方法内
|
||||
# 裸名解析为 0 → pool.alloc(8*0) 失败(TPV 编译测试 SUBS-NONE)。
|
||||
for _citem in Node.body:
|
||||
if isinstance(_citem, ast.AnnAssign) and isinstance(_citem.target, ast.Name) and _citem.value:
|
||||
_register_cdefine_constant(_citem.target, _citem.annotation, _citem.value)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
for target in Node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
|
||||
@@ -579,9 +579,19 @@ class CArray(CType):
|
||||
return cls
|
||||
|
||||
class CDefine(CType):
|
||||
"""编译期常量定义标记(X: t.CDefine = 64)。
|
||||
|
||||
Size/IsSigned 覆盖为 32 位有符号整数(2026-08-10 修复):基类 __init__
|
||||
将 Size/IsSigned 置 None,导致 CTypeToLLVM(CDefine) 推导为 'void',
|
||||
类字段注解 t.CDefine(如 Mixin 的常量声明)在 stub 生成时变成 void,
|
||||
LLVM struct 含 void 报 "void type only allowed for function results"。
|
||||
语义上 CDefine 常量即为 int;超大值由 TypeConvert 按 DefineValue 升 i64。
|
||||
"""
|
||||
position: ClassVar[frozenset[str]] = frozenset({CType.BASE})
|
||||
def __init__(self, value: Any = None) -> None:
|
||||
super().__init__(value)
|
||||
self.Size = 32
|
||||
self.IsSigned = True
|
||||
|
||||
class CPass(CType):
|
||||
position: ClassVar[frozenset[str]] = frozenset({CType.BASE})
|
||||
|
||||
Reference in new issue
Block a user